Follow my new blog

Posts mit dem Label Space Based Collaboration werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Space Based Collaboration werden angezeigt. Alle Posts anzeigen

Mittwoch, 10. Juni 2009

Asynchronizität und Verteilung üben - Szenarien für verteilte Anwendungen

Wer was Neues lernen will, tut das am besten zunächst mit Übungen. Chirurgen lernen neue Techniken erst an toten und/oder nicht menschlichen Lebewesen, Piloten lernen im Simulator. Und ich will den neuen Application Space ausprobieren oder allgemeiner asynchrone und verteilte Architekturen üben. Was sind aber Übungsaufgaben, an denen ich mich versuchen kann? Einen asynchronen und verteilten Service aufzusetzen ist ja trivial. Von dem Service dann auch noch Notifikationen zu bekommen oder Pub/Sub einzurichten, das ist auch trivial. Jeweils für sich genommen sind diese Dinge einfach - aber wie füge ich diese Bausteine zu etwas Größerem, Realistisch(er)em zusammen? Erst in einem umfassenderen Szenarion, das nicht von der Technik ausgeht, sondern von "Kundenanforderungen" kann ich auch feststellen, was einer Technologie wie dem Application Space noch fehlen mag (oder wo sie besonders geeignet ist).

Hier möchte ich nun einige Szenarien zusammentragen, die mir als Übungen für Verteilung und Asynchronizität erscheinen. Sie sind mehr oder weniger komplex, aber immer irgendwie "zum Anfassen". Jedes bietet für die zu übende oder evaluierende Technologie eine andere Herausforderung. Ich werde sie mit dem Application Space implementieren, wer mag, kann aber natürlich WCF pur oder mit Azure oder Jabber pur oder MassTransit oder NServiceBus oder Rhino Service Bus oder MSMQ pur oder TCP Sockets pur oder noch ganz andere Technologien damit ausprobieren. Ganz im Sinne der School of .NET Diskussion sehe ich diese Szenarien auch als Chancen für ganzheitliches Lernen. Clean Code Development, Komponentenorientierung, .NET Framework Grundlagen, TDD... all das und mehr kann man auch einfließen lassen.

Szenario 1: Stammdatenverwaltung

Aller Anfang sollte einfach und typisch sein. Deshalb ist mein erstes Szenario eines, mit dem viele Entwickler immer wieder konfrontiert werden: die Stammdatenverwaltung oder "forms over data". Ein Anwender verwaltet mit seinem Client Daten in einer Datenbank mit den üblichen CRUD-Funktionen: Create, Read, Update, Delete. Zusätzlich kann er einen serverseitigen Datenimport anstoßen.

Ob sich für dieses Szenario eine Verteilung überhaupt lohnt, sei einmal dahingestellt. Allemal, wenn aus anderen Gründen eine Anwendung verteilt werden soll, muss auch die Stammdatenverwaltung auf eine solche Architektur abgebildet werden.

Um das Datenmodell einfach zu halten, reicht es aus, wenn das Szenario sich nur um Personen mit ihrer Adresse dreht.

Datenmodell:

  • Person(Nachname, Vorname, Straße, PLZ, Ort, Land, Tel, Soundex)

Featureliste:

  • Der Anwender kann nach Personen suchen; der Server liefert eine Liste von passenden Personen zurück.
  • Der Anwender kann eine gefundene Person bearbeiten und speichern.
  • Der Anwender kann eine neue Person anlegen.
  • Der Anwender kann eine Person löschen.
  • Der Anwender kann gefundene Adressen in eine CSV-Datei exportieren. Der Export kann clientseitig erfolgen.
  • Der Anwender kann den Import von Personen aus einer CSV-Datei veranlassen. Dazu muss er dem Server mitteilen, in welcher Datei die Daten liegen. Der Server importiert, meldet zwischendurch den Fortschritt und liefert am Ende ein Importresultat.
  • Dublettenprüfung: Jede Person soll nur einmal in der Datenbank stehen. Mehrere Sätze mit denselben Daten sind zu vermeiden, um bei Mailings nicht mehrere Briefe an dieselbe Person zu senden. Um den Vergleich von Personen zu vereinfachen, können sie mit einem Soundex-Wert ausgestattet werden. Wannimmer eine Person gespeichert werden soll (nach Bearbeitung, nach Neuanlage, beim Import) und schon mit einem anderen Datensatz in der Datenbank vertreten ist, wird die Operation verweigert und der Anwender informiert. Die Dublettenprüfung kann in Schritten implementiert werden:
    • Dubletten bei Neuanlage prüfen
    • Dubletten beim Import prüfen
    • Dubletten nach Bearbeitung prüfen

Klingt doch einfach, oder? Hat aber natürlich seine Tücken, denn es gilt ja, diese Funktionalität asynchron und verteilt zu realisieren. Wie kommunizieren Client und Server im Sinne einer solchen Stammdatenverwaltung miteinander?

image

Herausforderungen:

  • Wie werden asynchrone Operationen wie Speichern oder Import im UI repräsentiert?
  • Wie meldet der Server den Fortschritt beim Im/Export an den Client (Notifikationen)?

Szenario 2: Referentenfeedback (Heckle Service)

Christian Weyer hat ein schon älteres Szenario in seinem dotnetpro-Artikel "Schnuppern an Azure" (5/2009)mit den aktuellen Technologien neu implementiert. In der dotnetpro 7/2009 greife ich das auf und realisiere es mit dem Application Space.

Die Idee ist einfach: Zuschauer eines Vortrags auf einer Konferenz sollen dem Referenten live Feedback geben können. Sie sollen sozusagen elektronisch zwischenrufen können (engl. to heckle). Dazu hat jeder Teilnehmer einen Client, mit dem er kurze Textnachrichten an den Referenten senden kann, der sie in einem eigenen Frontend auflaufen sieht.

Datenmodell:

  • Nachricht(Absendername, Nachrichtentext, Eingangszeitstempel) - Jede Nachricht gehört natürlich zu einem Referenten. Ob das allerdings in der Nachricht vermerkt werden muss, soll hier nicht festgelegt werden.

Featureliste:

  • Teilnehmer senden Zwischenrufe an den Referenten.
  • Teilnehmer sehen sich die Liste der letzten n Zwischenrufe an.
  • Der Referent bekommt jeden Zwischenruf automatisch angezeigt.
  • Falls der Referent sein Frontend - aus welchen Gründen auch immer - neu startet, bekommt er die Liste aller bisher eingegangenen Zwischenrufe angezeigt.
  • Der Referent identifiziert sich irgendwie, so dass die Teilnehmer ihm und keinem anderen ihre Zwischenrufe senden. Die Teilnehmer müssen einen Referenten also beim Zwischenrufen adressieren. Potenziell kann die Heckle-Anwendung ja gleichzeitig in vielen Vorträgen zum Einsatz kommen.
  • Der Veranstalter der Vorträge kann die Zwischenruflisten aller Referenten jederzeit einsehen.

image

Herausforderungen:

  • Wie nehmen Teilnehmer mit dem Referenten Kontakt auf? Direkt, indem sie seinen Rechner adressieren oder indirekt via eines Discovery-Servers?
  • Wo werden die Nachrichten vorgehalten, damit vor allem Teilnehmer und Veranstalter sich jederzeit einen Überblick verschaffen können?
  • Wie wird insb. der Referent automatisch über neue Nachrichten informiert?

Szenario 3: Tic Tac Toe

Es ist zwar kein typisches Geschäftsanwendungsszenario, aber es macht Spaß: ein Spiel realisieren. Bei Tic Tac Toe (TTT) sind die Regeln simpel, so dass man sich auf die verteilte Implementation konzentrieren kann.

Zwei Spieler spielen gegeneinander auf einem TTT-Brett. Jeder sitzt an seinem PC und sieht den gemeinsamen Spielstand.

Datenmodell:

  • Spielfeld mit 3x3 Spielfeldern in den Zuständen O, X und leer. Zusätzlich sollte das Spielfeld noch einen Spielzustand haben wie Spiel begonnen, Spiel beendet, Gewinner ist Spieler 1, Gewinner ist Spieler 2.

Featureliste:

  • Ein Spieler bietet sich zum Spiel an.
  • Ein Spieler nimmt Kontakt mit einem anderen auf und sie beginnen eine Partie.
  • Spieler machen Züge.
  • Ob und welcher Spieler gewinnt, wird automatisch festgestellt.
  • Ein Spieler beendet eine Partie vorzeitig.

Dies ist während des Spiels natürlich ein Peer-to-Peer-Szenario. Ob intern die Rollen aber auch gleich sind oder nicht vielleicht doch ein Spieler ein Partienserver ist, hängt von der Implementation ab.

image

Herausforderungen:

  • Wie nehmen die Spieler Kontakt miteinander auf?
  • Wo wird der Partienzustand gehalten?
  • Wie erfahren die Spieler über den nächsten Zug?
  • Wie wird den Spielern das Spielende mitgeteilt?

Szenario 4: Starbucks

Gregor Hohpe hat in einem Blogbeitrag deutlich gemacht, wie wenig praktikabel die bisher so beliebten 2-Phase-Commit-Transaktionen in der realen Welt, d.h. in asynchronen (und verteilten) Szenarien sind. MassTransit und Rhino Service Bus haben das aufgenommen und versucht, mit ihren Mitteln das Szenario abzubilden. Es ist einfach eine schöne Fingerübung für jeden, der in die verteilte und asynchrone Programmierung einsteigen will.

Bei Starbucks kommen Kunde, Kassierer und Barista zusammen. Der Kunde bestellt ein Getränk, der Kassierer nennt den Preis und nimmt das Geld entgegen. Währenddessen bereitet der Barista schon das Getränk zu und serviert es, wenn die Zahlung geklappt hat.

Datenmodell:

  • Bestellung(Getränkeart, Bechergröße, Menge)
  • Zahlungsaufforderung(Gesamtpreis einer Bestellung)
  • Bezahlung(Betrag, Zahlmittel) - Zahlmittel könnten Barzahlung oder Kreditkarte sein

Featureliste:

  • Kunde bestellt ein Getränk beim Kassierer. Variation: Kunde bestellt mehrere und verschiedene Getränke beim Kassierer.
  • Kassierer nennt den Gesamtpreis
  • Kunden bezahlt
  • Kassierer nimmt Bezahlung entgegen und prüft den Betrag. Wenn ok, dann schließt er die Bestellung ab.
  • Barista bereitet bestellte Getränke vor.
  • Wenn Bezahlung abgeschlossen, stellt der Barista die Getränke zur Abholung bereit.

Der Kunde kann hier als interaktiver Client realisiert werden. Kassierer und Barista hingegen sind automatische Dienste. Um die reale Welt nachzustellen, können ihre Funktionen über Pausen (Thread.Sleep()) eine wahrnehmbare Dauer bekommen.

image

Herausforderungen:

  • Wie nehmen die Beteiligten Kontakt miteinander auf?
  • Wie wird der Dialog zwischen Kunde und Kassierer geführt?
  • Wie erfährt der Kunde über das fertiggestellte Getränk?
  • Was passiert mit einem schon zubereiteten Getränk, wenn die Zahlung nicht erfolgreich ist?

Szenario 5: Arbeitsteilung

Das MSDN Magazine Juni/2009 beschreibt in "A Peer-To-Peer Work Processing App With WCF" ein Szenario, dass sich auch zur Übung zu realisieren lohnt. Mehrere sog. Worker stehen da bereit, um Aufträge von sog. Usern anzunehmen. Der Artikel nutzt zur Arbeitsverteilung das P2P-Protokoll von WCF - aber man kann es auch anders machen.

Datenmodell:

  • Arbeitsauftrag(Id, Dauer)

Featureliste:

  • User vergeben Aufträge in einen Pool von Workern hinein.
  • Worker übernehmen einen oder mehrere Arbeitsaufträge.
  • Worker können dem Pool beitreten oder ihn verlassen.
  • Ob ein Worker Aufträge annimmt hängt von seiner Last ab. Die gesamte Auftragslast soll natürlich möglichst gleichmäßig auf die Worker verteilt werden.
  • Wie die Arbeit "so läuft" können sog. Spectators beobachten; sie dienen der Instrumentierung des Systems.

In dieser Featureliste fehlen einige Aspekte, die der Artikel beschreibt, z.B. "Work Item Backup" oder "Work Sharing". Ich habe sie nicht aufgenommen, weil sie mir abhängig scheinen vom gewählten Lösungsweg (hier: P2P-Kommunikation). Meine Szenarien sollen aber keine Lösungswege oder Technologien nahelegen (z.B. Einsatz eines Busses oder Sagas oder P2P-Kommunikation).

Die schlanken Aufträge habe ich ebenfalls deshalb übernommen. Es geht ja nicht um eine konkrete Problemdomäne. So müssen die Aufträge nur eine Dauer haben, um Lastverteilung beobachten zu können.

image

Herausforderungen:

  • Wie wird die Auftragslast möglichst gleichmäßig (oder "gerecht") auf die Worker verteilt?
  • Wie werden weitere Worker möglichst unmittelbar in die Auftragsbearbeitung einbezogen? Oder allgemeiner: Wie kann der Worker-Pool "atmen"?
  • Wie werden User über Auftragsergebnisse (oder gar Fortschritte) informiert?
  • Wie kann ein Spectator die Arbeit(sverteilung) beobachten?
  • Müssen Aufträge nach Vergabe noch "gesichert" werden können, falls Worker noch nicht zu ihrer Verarbeitung gekommen sind?
  • Wie können die Worker möglichst ortsunabhängig verfügbar gemacht werden?

Samstag, 23. Mai 2009

Auf ins Raumzeitalter! - Asynchron und verteilt mit dem Application Space

Software verteilen ist keine leichte Sache. Muss das so sein? Nein, ich glaube nicht. Wir machen es uns nur selbst unnötig schwer, indem wir immer wieder und weiter versuchen, in verteilten Systemen genauso zu kommunizieren, wie in lokalen. Corba, DCOM, .NET Remoting, Webservices, WCF: sie stehen alle in derselben Tradition. Sie alle favorisieren die synchrone, methodenbasierte Kommunikation zwischen entfernten Funktionseinheiten. Ihr Credo: Wenn service.TueEtwas() lokal der Ausdruck eines Servicewunsches ist, dann sollte das auch in verteilten Systemen so sein.

Bei aller Nachrichtenorientierung, in der inzwischen WCF angekommen ist, halte ich das jedoch für falsch. Darüber habe ich auch schon ausführlich hier im Blog geschrieben. Nur wie können wir es anders machen?

Klar, es gibt Alternativen. Es gibt Technologien für asynchrone, nachrichtenorientierte, event-driven Architekturen. MSMQ/System.Messaging gehört dazu und aufbauend darauf z.B.  Mass Transit oder NServiceBus. Von größeren und teureren Werkzeugen will ich gar nicht reden.

Trotz dieser Ansätze bin ich jedoch nicht zufrieden gewesen. Denn Messaging - obwohl das für die Verteilung  "ehrlichere" Konzept als der Methodenaufruf - ist irgendwie auch einschränkend und immer etwas schwergewichtig. Die Einschränkung liegt im Fokus auf den "Röhren" zwischen Funktionseinheiten. Die halte ich aber für einen Sonderfall. Und die Schwergewichtigkeit liegt im API. Messaging ist eben eng verbunden mit MSMQ. Und Messaging konzentriert sich auf die Verteilung.

Nun bin ich froh, sagen zu können, dass meine Zufriedenheit gerade sehr gestiegen ist. Denn ein Projekt, an dem ich schon einige Zeit beteiligt bin, trägt nun erstmalig öffentliche Früchte. Zusammen mit der TU Wien kann ich im Rahmen der Xcoordination Unternehmung (www.xcoordination.com) bekannt geben, dass wir die erste CTP unseres Xcoordination Application Space (AppSpace) bei CodePlex veröffentlicht haben: http://xcoappspace.codeplex.com.

Nach Vorversuchen und Andeutungen ist nun live, wovon wir meinen, dass es das Verteilen von Software sehr viel einfacher machen kann. Der AppSpace ist damit einerseits tatsächlich als Ersatz für z.B. WCF gedacht - auf der anderen Seite lieben wir aber auch WCF.

WCF ist cool. WCF ist breit und tief und universell. Das ist super! Aber wir glauben nicht, dass WCF einen API bietet, den der Durchschnittsentwickler direkt nutzen sollte, um seine Software zu verteilen. Der Preis für WCFs Mächtigkeit ist schlicht Komplexität und damit geringe Usability.

Der AppSpace verbirgt diese Komplexität nun. Er bietet aufbauend auf WCF und anderen Kommunikationstechnologien einen API für die lokale wie die verteilte asynchrone Programmierung. Er abstrahiert von den Feinheiten der WCF.

image

Wir meinen, dass damit ein Sprung in der Verteilung von Software geschafft werden kann wie vom Win16/Win32 API zu VB1.0. 1990 konnte man Windows programmieren - aber es war sauschwer, mit dem Windows API in C direkt umzugehen. Nur Experten konnten also das Potenzial graphischer Benutzerschnittstellen ausnutzen.

Dann kam VB1.0 und alles wurde anders. Mit VB1.0 konnten plötzlich Millionen von Entwicklern graphische Benutzerschnittstellen programmieren. Dazu mussten Sie zwar gegenüber den bisherigen umdenken - Stichwort "Event-Driven UI" -, aber das war nicht so schlimm.

Ähnlich sehen wir den AppSpace. (Ein bisschen Größenwahn kann nie schaden, oder? ;-) Mit dem Programmiermodell des AppSpace hoffen wir auch, die Verteilung von Code einer viel größeren Gruppe von Entwicklern zugänglich zu machen.

Dazu ist zwar auch ein Umdenken nötig - Stichwort "Asynchrone Kommunikation" -, aber das wird hoffentlich nicht so schlimm. Vor allem ist der Gewinn doppelt, wenn man sich auf diesen Paradigmenwechsel von synchron nach asynchon einlässt. Nicht nur wird die Verteilung einfacher, man bekommt auch noch die lokale Parallelverarbeitung gleich dazu.

Und warum soll nun der AppSpace der Bringer sein gegenüber anderen Messaging-Technologien? Weil sich der AppSpace eben nicht nur um Messaging dreht. Messaging ist für ihn ein Sonderfall. Oder Messaging passiert für ihn "unten drunter".

Das zentrale Konzept beim AppSpace sind vielmehr Dienstleistungskomponenten. Er bleibt also so dicht wie möglich an der Objektorientierung und der synchronen Komponentenorientierung. Deshalb bietet er auch eine DI Container Schnittstelle. Er holt die Entwickler da ab, wo sie heute stehen: bei den synchronen Komponenten. Und dann bietet er ihnen schrittweise mehr. Zuerst unterstützt er sie auf der Basis der Microsoft Concurrency Runtime dabei, von lokal synchron auf lokal asynchron umzusteigen. Und dann unterstützt er sie beim Umstieg von lokal asynchron zu entfernt asynchron.

Das halten wir für eine natürliche Progression im Denken und in der Codierung. Wer gelernt hat, lokal asynchron zu programmieren, der hat viel weniger Probleme, wenn es dann an die Verteilung von Code geht. Mit dem AppSpace bekommt er die Verteilung dann sozusagen geschenkt.

Für die, die nun ganz gespannt darauf sind, wie denn der API des AppSpace aussieht, hier ein Codeschnippsel. Mehr gibt es bei CodePlex und demnächst in der dotnetpro. Auch Beispielprojekte werden wir bei CodePlex einstellen.

So sieht der Kontrakt eines ganz simplen asynchronen Dienstes aus, der z.B. eine Zeichenkette empfängt und serverseitig ausgibt. Das ist trivial von der Funktionalität her. An dieser Stelle möchte ich aber nur zeigen, wie schlank der AppSpace API ist.

Asynchrone Komponenten haben keine Methoden, die man direkt aufrufen könnte, sondern definieren einen Satz von Nachrichten (Message Contract), die sie über typisierte Microsoft CCR Ports empfangen.

using Microsoft.Ccr.Core;
using XcoAppSpace.Core;

public class PPingContract : Port<string>
{}

Das ist die Implementation dies Kontraktes. Eine Klasse vom Kontrakt ableiten und für jede Nachricht eine Behandlungsroutine definieren:

public class PingService : PPingContract
{
    [XcoConcurrent]
    void ProcessPing(string text)
    {
        Console.WriteLine("processing: {0}", text);
    }
}

Und jetzt der Host für die Serviceimplementation. Zwei Zeilen Code reichen aus. Die asynchrone Dienstleistung "läuft" in der Instanz eines Application Space:

using(XcoAppSpace host = new XcpAppSpace("tcp.port=9001"))
{
    host.RunWorker<PPingContract, PingService>("pingservice");
    Console.ReadLine(); // keep the host running while waiting for connections
}

Der Client ist dazu symmetrisch! Das ist einer der Vorzüge des AppSpace. Das macht ihn einfach zu bedienen, weil die Zahl der zu lernenden Konzepte so überschaubar ist:

using(XcoAppSpace client = new XcoAppSpace("tcp.port=0"))
{
    PPingContract p = client.ConnectWorker<PPingContract>("localhost:9001/pingservice");

    p.Post("hello, world!");

    Console.ReadLine(); // keep client alive
}

Das ist´s so ziemlich. Wenn Sie den Code verstanden haben (und die CCR Grundlagen kennen), dann können Sie mit dem AppSpace lokal asynchron oder verteilt asynchron arbeiten. Rückhabewerte, Notifikationen, Publish/Subscribe... das alles ist mit den immer gleichen Mitteln leicht zu realisieren. Schauen Sie mal bei CodePlex vorbei, wo ich dieses Beispiel noch etwas ausgebaut habe.

Laden Sie den AppSpace aus dem Download-Bereich herunter und spielen Sie mal damit. Ich freue mich über jedes Feedback. Bei allem Anspruch ist der AppSpace ja nicht fertig. Er ist erst am Anfang. Wir bei Xcoordination glauben aber, dass die Richtung stimmt. Wenn Sie wollen, gehen Sie in diese Richtung mit. Erste kommerzielle Projekte sind schon vorausgelaufen und melden zurück, dass es sich lohnt. Bei CodePlex und www.xcoordination.com gibt es viel Platz zum Diskutieren. Und außerdem ist der Application Space eine Open Source Software. Die können Sie aber sogar kostenlos in Ihren kommerziellen Closed Source Projekten einsetzen.

Also, auf ins Raumzeitalter mit dem Application Space! Verteilung die einfach funktioniert.

Donnerstag, 26. Juni 2008

Bound in Space - Skizze der Kommunikation in einem Application Space

Komponenten verteilen, Komponenten parallel arbeiten lassen und überhaupt Software aus Komponenten aufbauen sollte viel, viel einfacher werden. Denn nur dadurch würden sich diese Konzepte breiter durchsetzen. Und nur dadurch würde Software in größerer Menge performanter, skalierbarer, testbarer, evolvierbarer. Dafür habe ich in meinem gestrigen Posting eine Lanze gebrochen.

Heute möchte ich zu dieser Vision eines Application Space (AppSpace) ein Bild zeichnen. Ich stelle mir vor, dass Software in Zukunft sehr einheitlich und ganz grundsätzlich so organisiert sein sollte:

image

Die Grundbausteine von Software sind Komponenten. (Klassen sind auch wichtig, aber unterhalb der Wahrnehmungsschwelle von Softwarearchitekten.) Definieren wir sie einfach mal als binäre Codeeinheiten mit separater Leistungsbeschreibung (Kontrakt). Wenn Sie jetzt "Assembly" denken, liegen Sie nicht falsch.

Diese Komponenten "leben und arbeiten" in etwas, das ich mal Compartment nennen. Solche "Abteile" teilen einen Raum, deshalb finde ich den Begriff ganz passend in Bezug auf die Raum-Metapher, die hinter Application Space steht.

Wie diese Komponenten in den Abteilen aufgehängt sind, ist zunächst einmal nicht so wichtig. Hauptsache, sie haben erstmal ein "Zuhause", in dem manche "zusammen leben" und andere eben in anderen "Zuhauses". (Hm... vielleicht wäre "Appartment" besser als "Compartment"? Dann könnten Komponenten in einer WG leben :-)

Innerhalb der Compartments können Komponenten direkt miteinander kommunizieren, einfach über Methodenaufruf. Sie liegen im selben "Abteil" dicht beisammen (im selben Adressraum) und können daher den Stack nutzen. Alles ist, wie Sie es kennen und lieben. Einzig, die Verbindung zwischen zwei Komponenten wird durch einen DI Framework bzw. Microkernel hergestellt. Den bietet das Compartment als komponentenumfassender Kontext; das ist eine seiner Infrastrukturleistungen.

Wie Sie Compartments auf Prozesse oder Maschienen oder gar Netzwerke verteilen, ist zunächst einmal unerheblich. Das sind Feinheiten des Deployments. In einem AppSpace gilt: Was in einem Compartment gehostet wird, liegt nah beieinander in einem Adressraum, der direkte Kommunikation erlaubt. Deshalb können Sie auch entscheiden, ob Compartments das noch durch eigene AppDomains unterstreichen sollen. Kann sein, muss aber nicht.

Fangen Sie mit 3 Compartments in einem Prozess an und verteilen Sie sie später auf 3 Prozesse. Oder führen Sie Redundanz ein, indem Sie sie auf 7 Prozesse verteilen. Welcher Art die Prozesse sind - also IIS oder NT Service oder Console EXE usw. - ist dabei nicht so wichtig. Diese Compartment Hosts müssen einfach zum Zweck der darin "lebenden" Komponenten passen.

Wegen dieser Flexibilität fehlen im obigen Bild auch Prozesse und Maschinen und Netzwerke. Denn das Credo des AppSpace ist, dass diese Deploymenteinheiten zweitrangig sind. Erstrangig ist hingegen, ob eine Komponente synchron und nah bei anderen läuft oder asynchron und fern von anderen. Darüber gibt ein AppSpace-Diagramm jedoch Auskunft.

Synchrone Komponenten sind einfach - selbst wenn Sie DI benutzen. Asynchrone Komponenten jedoch... da wird es knifflig. Wie sollen die miteinander kommunizieren? Die Asynchronizität beginnt schon, wenn zwei Objekte auf separaten Threads laufen. Sie wird schlimmer, wenn diese Objekte in verschiedenen AppDomains hängen und noch übler wird´s, wenn sie durch Prozesse, Maschinenen oder Netzwerke getrennt sind.

Heute stehen dafür eine Reihen unterschiedlicher Technologien zur Verfügung. Da gibt es eine Pallette von Möglichkeiten, Parallelität einzuführen. Wenn Ihre Anwendung in mehrere Prozesse zerlegt ist, ergibt sich die ganz natürlich. Ansonsten können Sie Threads aber auch von Hand auf die eine oder andere Weise erzeugen. Aber Achtung: nicht zuviele, sonst ist die ganze Asynchronizität kontraproduktiv.

Vielfältiger sind die Möglichkeiten für die Kommunikation zwischen den Threads. Die kann über´s Dateisystem laufen oder gemeinsame Objekte (shared memory), rohe TCP Sockets funktionieren genauso wie WCF.

Diese Vielfalt der Kommunikationsmedien, so verständlich sie ist, halte ich nun inzwischen für nachteilig. Niemand kennt sich mehr aus. Ich plädiere daher für eine radikale Vereinfachung durch Vereinheitlichung, mit der sich vielleicht 80% aller verteilter Kommunikation lösen lässt. Nein, nicht 100%, aber ich sag mal optimistisch 80%. Mir liegt daran, Asychronizität "den Massen" nahezubringen und nicht wirklich jedem zu jeder Zeit die Entscheidung zwischen vielen Optionen aufzubürden.

Die Technologievielfalt kann und soll also erhalten bleiben - unter der Haube. Wer sie braucht, um im Einzelfall mal performanter zu sein, hat sie dann. Aber der allgemeine Fall wird durch Abstraktion einfacher. So wie es schon viele Male in der Geschichte der Softwareentwicklung geschehen ist. Beispiel SQL, Beispiel O/R Mapping, Beispiel GDI+ usw. usf.

Wie soll nun diese Vereinfachung der Kommunikation zwischen asynchronen Komponenten aussehen? Das obige Bild zeigt es: Neben der direkten Kommunikation innerhalb eines Compartments gibt es die indirekte (!) zwischen Compartments. Indirekt ist sie immer, wenn Komponenten asynchron zu anderen laufen. (Insofern kann auch innerhalb desselben Compartments indirekt kommuniziert werden.)

Indirekte Kommunikation bedeutet, dass eine Client-Komponente nicht (!) direkt mit einer Service-Komponente spricht. Client und asynchroner Service sind vielmehr immer (!) durch einen Vermittler verbunden. Im einfachsten Fall ist dieser Vermittler eine Warteschlange, eine Queue. Aber das ist nur der einfachste oder übliche Fall. Ein AppSpace ist nicht darauf beschränkt. Zwischen Client und Service können alle möglichen Vermittlerformen stehen: Queue, Stack, Baum, relationale Tabelle, Liste, Array, Dictionary... you name it.

Gemeinsam ist allen Vermittlern nur, dass sie Datenstrukturen sind. Die eine Komponente manipuliert sie, die andere beobachtet sie. Und dann können die Rollen wechseln. Beobachtung ist entweder aktiv (polling) oder passiv (Ereignisgesteuert, Stichwort: EDA).

Diese Datenstrukturen existieren virtuell im AppSpace und sind für alle Komponenten in allen Compartments grundsätzlich zugänglich. Deshalb liegen die Winkel der asynchronen Kommunikation im obigen Bild im Space.

Implementationstechnisch sieht das jedoch anders aus. Da liegen die Vermittlerdatenstrukturen ebenfalls in Compartments, sozusagen in einem Gürtel um sie herum.

image

Letztlich ist es aber egal, wo genau diese Datenstrukturen, die Container hängen. Sie können nach dem Prinzip "write remote, read local" immer beim asynchronen Service angesiedelt sein (also im Compartment der Pfeilspitze einer Verbindung zwischen zwei Komponenten). Oder sie können auch in einem ganz anderen Compartment liegen:

image

Container werden im AppSpace gegenüber Anwendungscode nicht durch eine Adresse repräsentiert, sondern durch einen AppSpace-globalen Namen.

Der AppSpace macht Komponenten insofern nicht nur durch DI implementationsunabhängig voneinander, sondern auch unabhängig in Bezug auf Ort und Zeit. Durch Container als Vermittler stehen Komponenten nicht mehr direkt in Kontakt, d.h. beide müssen nicht mehr gleichzeitig "anwesend" sein im AppSpace. Und AppSpace-weite Containernamen verbergen den genauen Ort (Compartment, AppDomain, Prozess, Maschine, Netzwerk), an dem eine asynchrone Komponente "lebt".

Nach der grundlegenden Entscheidung, ob Komponenten synchron oder asynchron kommunizieren sollen, kann die Topologie sich bei asynchronen Komponenten sehr weitreichend ändern, d.h. wechselnden Bedürfnissen anpassen, ohne dass Client-Anwendungscode davon betroffen wäre.

Der AppSpace soll also die Vorteile von EDA verallgemeinern (nicht nur Queues, sondern auch andere Datenstrukturen, auf die man lauschen kann) und mit Komponentenorientierung wie Computing in/via the Cloud verschmelzen. Ich sehe ihn als Aggregat vieler existierender Technologien, die er unter einer Abstraktionsdecke versteckt.

Insofern bietet ein AppSpace einen schönen Migrationspfad: Ich kann mit ihm anfangen und erstmal nur Komponenten in einem Compartment verbinden. Dann kann ich in die Asynchronizität klein einsteigen, indem ich mal im selben Compartment eine Komponente asynchron mache. Und dann kann ich die Asynchronizität ausdehnen auf mehr Komponenten. Und dann kann ich diese Komponenten verteilen. Schließlich laufen sie auf vielen Rechnern übers LAN oder gar Internet verteilt. Ohne, dass mein Applikationscode davon etwas merken würde. Denn sobald ich einmal mit der asynchronen, containervermittelten Kommunikation angefangen habe, skaliert die von der cross-thread bis zur cross-firewall Kommunikation. Das Geheimnis liegt darin, dass sie nicht nur nachrichtenorientiert, sondern eben datenstrukturvermittelt ist.

Mittwoch, 25. Juni 2008

Asynchrone Architekturen einfacher machen - Umriss eines Application Space

In meiner vorherigen Posting habe ich ja eine Lanze für mehr Asynchronizität gebrochen. Die halte ich für wünschenswert und notwendig - aber einfach herzustellen ist sie heute noch nicht. Man kann es, es gibt viele "Splittertechnologien", aber die sind nicht "at our fingertips".

Bezüglich asynchroner Architekturen sind wir noch in einer "vor-bequemen Zeit", also etwa wie bei der Persistenz so um 2002 herum. Da gab es noch keine O/R Mapper für .NET und kein noch einfacher zu nutzendes db4o oder Persistor.Net.

Der ThreadPool, der AsyncOperationManager, die CCR, WCF... diese und andere Technologien machen es uns heute schon einfacher, asynchron sowohl lokal wie verteilt zu arbeiten. Dennoch: insgesamt sind sie mir noch zu kompliziert. Das liegt zum Teil an den APIs - die wollen jeder für sich one-size-fits-all Lösungen sein -, andererseits liegts am Konzept dahinter. WCF mag zwar nachrichtenorientiert sein - sehen tut man das aber nicht wirklich. Da helfen auch keine Data Contracts.

Um die gläserne Decke der Synchronizität nicht zu durchbrechen, sondern sie schlicht auf dem Weg zu mehr Performance und Skalierbarkeit zu umgehen, wünsche ich mir deshalb eine Infrastruktur, die Asynchronizität viel einfacher macht. Hier mal ein paar Punkte, die sie für mich minimal erfüllen müsste:

  • Einfache lokale Kommunikation zwischen Komponenten; Stichworte: Contract-first Design, Dependency Injection und Microkernel
  • Einfache verteilte Kommunikation; Stichworte: Nachrichtenorientierung, Event-Driven Architecture, "Datenstrukturorientierung" statt Serviceorientierung
  • Einfache Änderung der Topologie von Netzen verteilter Komponenten; Stichworte: Service Discovery, Unterstützung verschiedener Transportprotokolle, location transparency
  • Einfache Verteilung "in the cloud"; Stichworte: Tunnelung von NAT und Firewalls
  • Einfaches Hosting von Komponenten in unterschiedlichen AppDomains
  • Einfache Verteilung der Arbeit auf mehrere Threads

Dahinter stehen für mich ein paar Ansprüche, wie ich arbeiten/denken können möchte:

- Ich glaube, dass echte Komponentenorientierung durch Infrastruktur unterstützt werden muss. Sie stellt sich nicht von allein ein, sondern muss quasi durch Technologie "nahegelegt" werden. Visual Studio oder der .NET Framework tun das bisher nicht.

- Eine komponentenorientierte Infrastruktur soll das Laden von Komponenten einfach machen und auch die Kommunikation zwischen Komponenten.

- Bei der Komponentenorientierung möchte ich zunächst nicht zwischen lokalen und entfernten Komponenten unterscheiden. Beide sollten also durch dieselbe Infrastruktur unterstützt werden.

image - Für die Kommunikation zwischen Komponenten glaube ich allerdings fest daran, dass sie erstens zwischen lokalen und verteilten Komponenten ganz anders (!) aussehen sollte (s. dazu auch meinen Beitrag in "SOA Expertenwissen"). Und zweitens glaube ich, dass sie für verteilte Komponenten viel einfacher und einheitlicher werden sollte, als mit .NET Remoting oder auch WCF der Fall. Diese Einheitlichkeit und Einfachheit mag dann nicht 100% aller Probleme lösen, aber 80% sollten damit viel leichter zu erschlagen sein.

- Verteilte Komponenten möchte ich genauso einfach auf verschiedenen Threads wie in verschiedenen AppDomains oder auf verschiedenen Rechnern laufen lassen. Selbst wenn das Internet - the cloud - zwischen ihnen stehen sollte, darf sich nichts an ihrer Kommunikation ändern.

- Für einfache Verteilung ist es auch wichtig, dass ich die Wahl habe zwischen Push und Pull, um an Informationen zu kommen. Ich möchte selbst Last ganz einfach verteilen können, also nicht auf eine Cluster-Infrastruktur angewiesen sein. Warum kann ich nicht einfach heute einen Rechner als Server irgendwo in der Welt hinstellen und morgen 2, 3, 4 weitere irgendwo anders in der Welt - und alle teilen sich die Last? Klar, das geht schon... aber nicht so einfach. Da kann ich nicht nur schnell mal 'nen Service Contract mit WCF aufsetzen. Solche Flexibilität möchte ich aber haben.

Bottom line: Für mich müssen "Komponentendenke", Verteilung auf kurze und weite Distanz und Parallelität in einem einfachen 80%-Werkzeug zusammenkommen. Dabei gehts nicht darum, ein Rad neu zu erfinden, sondern vorhandene Ränder (endlich) zu einem Auto für jedermann zusammenzustecken. Bekanntes, Vertrautest, Bewährtes soll in Synergie zusammenarbeiten und in der Summe mehr sein, als die Teile vermuten lassen.

image Alles beginnt dabei mit... Einfachheit. Wir brauchen heute nicht leistungsfähigere Technologien, sondern vor allem einfachere. Sonst bleiben zuviele Entwickler zurück. Sie haben nicht die Zeit, sich in Kompliziertes einzuarbeiten. Kommen die Aspekte Komponentenorientierung, Verteilung und Parallelität nicht zusammen, dann nutzen nur wenige das Potenzial, das in Multi-Core Prozessoren und dem universalen Internet steckt.

Mit einem Application Space (AppSpace) wie oben skizziert, sähe das jedoch anders aus. (Ich könnte ihn auch Integration Space oder Component Space nennen. Application Space klingt für mich aber im Augenblick handlicher, weniger out-spaced ;-) Er wäre für komponentenorientierte, asynchrone Software das, was db4o für die Persistenz ist: ein "Ermöglicher" (enabler), der für viele erstmals etwas in Reichweite rückt, was ihnen bis dahin akademisch oder schwierig erschienen oder gar unbekannt war.

Dienstag, 12. Februar 2008

Space Based Collaboration - Jetzt mit mehr Öffentlichkeit

So langsam nimmt die WCF-Alternative doch Fahrt auf. Oder besser: die nächste Abstraktionsstufe oberhalb von WCF. Vor ein paar Jahren waren Spaces nur eine recht akademische Idee. Jetzt aber finden sie den Weg in die Öffentlichkeit. Der Beginn eines neuen Paradigmas.

Neulich hatte ich schon ein paar Gedanken zu einer Technologie nach bzw. komplementär zu WCF geäußert. In die selbe Richtung gingen davor auch schon meine Spekulationen über eine neue Klasse von Anwendungen: serverless real-time online collaborative (SROC) applications. Die scheinen nämlich von Spaces als Grundlage für die Kollaboration besonders profitieren zu können.

Als ich 2006 schon einmal über "Life Beyond WCF" und Virtual Shared Memory geblogt hatte, waren Spaces auch noch weniger greifbar. Aber nun hat Amazon einen Tuple Space in die Öffentlichkeit entlassen - mehr dazu in einige Postings in meinem englischen Blog - und das rennomierte Portal "The Serverside" hat (mithilfe des Space-Produktanbieters GigaSpaces) ein eigenes Knowledge Center zum Thema aus der Taufe gehoben. Das machen die ja nicht, wenn da kein Potenzial wäre.

Alles sehr schöne Entwicklungen wie ich finde :-) Weiter ermutigt hat mich auch ein Abend bei der .NET User Group Hamburg: Da habe ich neulich 2,5 Stunden eine Space Implementation diskutiert und demonstriert - und die Teilnehmer waren sehr interessiert bei der Sache. Die Aussicht, eine Alternative zu WCF auf höherem Abstraktionsniveau in die Hände zu bekommen, fanden fast alle sehr attraktiv. Ein besonderer Glücksmoment war dann, als ein Teilnehmer zu dem Chat-Beispiel, das ich live gebastelt hatte sagte, das sei der kürzeste Code für die Chat-Funktionalität, den er je gesehen hätte. Seufz... genau das wollte ich nämlich rüberbringen: Space Based Collaboration macht Code für die Kommunikation in verteilten Anwendungen kürzer und leichter zu lesen und intuitiver.

image

Nach so positivem Feedback aus der User Group freue ich mich nun, das Team hinter der Implementation auch einmal zeigen zu können. Es hat jetzt nämlich selbst eine Presseveröffentlichung herausgegeben und ist online mit einer Projektbeschreibung zu finden. Rechts zu sehen die Helden der XcoSpaces, der .NET-Implementierung der Space Based Collaboration: Prof. Eva Kühn (vorne rechts) ist die Initiatorin und Koordinatorin des Projektes und unermüdliche Verfechterin des Space-Paradigmas seit vielen Jahren; und Thomas Scheller (vorne links) zusammen Markus Karolus (dahinter) haben die XcoSpaces tapfer implementiert. Es macht Spaß, mit dem Team an der Idee zu arbeiten und sie aus der akademischen in die praktische .NET-Welt zu tragen.

Wer nun neugierig geworden ist, was es denn mit Spaces auf sich hat, der melde sich gern bei mir via Email oder per Blog-Kommentar. Der XcoSpaces-Prototyp zweiter Generation ist für Interessenten kostenlos erhältlich. Eva Kühn et al. und ich sind sehr daran interessiert, Erfahrung im Einsatz von Spaces in realen Problemszenarien zu sammeln.

Donnerstag, 31. Januar 2008

Was kommt nach WCF? Gedanken über die Grenzen der Nachrichtenorientierung

Um es gleich vorweg zu sagen: Ich find WCF schon toll. Aber - und dieses aber ist mir wichtig - WCF lässt in mir kein Gefühl von "angekommen sein" entstehen.

Toll an WCF ist die Vereinheitlichung, die es erreicht hat. COM+/Enterprise Services, .NET Remoting, Web Services und MSMQ sind in WCF zu einem konsolidierten Programmier- und Kommunikationsmodell zusammengeflossen. Äußerlich ist der Unterschied zwar marginal - es werden wie seit der Erfindung von RPC immer noch entfernte Funktionen direkt aufgerufen. Doch die konsequente Nachrichtenorientierung ist der Natur entfernter Kommunikation wesentlich angemessener als die bisherigen Versuche der Objektorientierung, ihren Siegeszug bei der in-process Kopplung von Codeeinheiten auch auf die cross-process oder gar cross-platform Kopplung auszudehnen. Corba, EJB, .NET Remoting heißen diese letztlich gescheiterten Versuche. RIP.

Also: WCF ist toll. Und doch...

Es will sich bei mir kein wohliges Gefühl der Zufriedenheit einstellen. Die Vereinheitlichung ist mir irgendwie nicht genug. Vereinheitlichung war zwar ein wichtiges Ziel, ebenso der konsequente Abschied von "verteilten Objekten" - aber ist WCF deshalb gleich das Ideal? WCF ist vielleicht der beste vereinheitlichte nachrichtenorientierte API, den es gibt.  Aber wollen wir eigentlich Nachrichtenorientierung? Ist funktionsbasierte Nachrichtenorientierung als einziges Kommunikationsmodell zwischen verteilten Codeeinheiten wirklich das wünschenswerte Abstraktionsniveau?

Ich werde das Gefühl nicht los, dass "es" noch anders gehen könnte und sollte. Zumindest als Alternative, wenn nicht als pauschaler Ersatz für WCF. Um das Gefühl mal zu konkretisieren, hier einige Punkte, die mir bei WCF aufstoßen. Lobeshymnen hören wir ja häufig genug. Also:

  • WCF ist unehrlich
  • WCF ist anti-autonom
  • WCF ist kompliziert
  • WCF ist starr
  • WCF ist unintuitiv

So ganz allein stehe ich mit meiner Meinung, dass WCF bzw. allgemeiner die Nachrichtenorientierung irgendwie noch nicht das Ende der Fahnenstange sein kann, wohl auch nicht. Das renommierte Portal "The Service Side" (TSS) hat gerade ein "Space Based Architecture Knowledge Center" eingerichtet und Amazon hat unlängst einen Tuple Space (SimpleDB) als Beta in sein SaaS-Angebot gehoben. (Mehr zum Thema SimpleDB in bei meinem Open Source Projekt NSimpleDB.)

Spaces - so die Botschaft von TSS (mithilfe des Infrastrukturanbieters Gigaspaces) und Amazon - sind eine Alternative zur Nachrichtenorientierung. Spaces und Räume statt der ewigen Röhren. Warum nicht? Dem Gedanken bin ich sehr zugetan. Deshalb bastle ich mit an einem "Space-Angebot" - das aber noch eine Weile bis zum großen Auftritt brauchen wird. Deshalb habe ich das SimpleDB Datenmodell mit NSimpleDB auf den Desktop gebracht, um es leichter für Experimente verfügbar zu machen. Denn Experimente sind noch nötig, um die Reichweite des Space-Paradigmas abzustecken. In dieser Linie sehe ich auch dieses Posting: Als ein lautes Nachdenken über Space Based Architecture (SBA) oder Space Based Computing (SBC) oder Space Based Collaboration (SBC), mit dem ich mir selbst wieder ein Stückchen klarer über Nutzen und Grenzen von SBC/SBA werde. Ein probater Anfang ist dafür wie immer, mal die "pain points" zu benennen, wo mich das Existierende sticht.

WCF ist aus meiner Sicht unehrlich, weil ich die Syntax des Methodenaufrufs für das falsche Mittel halte, um einen Auftrag an eine entfernte Codeeinheit zu übermitteln. Einer Anweisung wie

resp = service.TueEtwas(req);

kann ich nicht ansehen, ob der Service lokal oder remote läuft. Läuft er aber remote, dann leistet die Syntax den vielzitierten "Fallacies of Distributed Computing" massiven Vorschub. Das halte ich für essenziell nachteilig im Hinblick auf Wartbarkei und Verständlichkeit und womöglich auch Skalierbarkeit und Performance. Ausführlich habe ich diesen Gedanken in einem Beitrag [PDF] für "SOA Expertenwissen" dargelegt.

In dem Beitrag erkläre ich auch, warum diese Form der "Auftragsübermittlung" für mich grundlegend anti-autonom ist. Sie formuliert einen Befehl, dessen syntaktische Form danach heischt, sofort ausgeführt zu werden. Sofortigkeit steht jedoch zum Einen im Widerspruch zur physikalischen Realität der Verteilung von Client und Service, zum Anderen ist sie aber auch unvereinbar mit dem simplen Hauptgrund einer Verteilung überhaupt: Autonomität. Verteilte Codeeinheiten sind verteilt, damit sie möglichst autonom über ihre Prozesse und Ressourcen entscheiden können. Wer jedoch autonom ist, der will sich nicht vorschreiben lassen, wann und wie genau er einen Dienstleistungswunsch erfüllt. Solchen Freiraum bietet die Form der Nachrichtenorientierung in WCF jedoch nicht.

Nun mag man das alles für Haarspalterei halten. Das fände ich zwar schade, weil Form und Funktion, Syntax und Semantik in einem Gleichklang stehen sollten. Wenn sich die Funktionsweise in der Form widerspiegelt, wenn klar erkennbar ist, wie etwas funktioniert, dann ist das Bild kohärent und wirkmächtiger. Dann ist weniger Raum für Missverständnisse.

Aber sei´s drum. Deshalb hier zwei hoffentlich handfestere Kritikpunkte: Ich finde WCF recht einfach für Allereinfachstes, aber kompliziert für sehr Typisches. Typisch sind für mich z.B. die asynchrone Benachrichtigung über Ereignisse in einem Service, typisch sind für mich daraus folgende Aufrufe des Service. Beides ist natürlich mit WCF möglich. Aber ich finde es recht kompliziert. Für eine simple Notifikation muss ich plötzlich über Duplexkommunikation nachdenken und ein Rückrufinterface registrieren. Und wenn ich dann in so einem Event den Service aufrufen möchte, dann geht es plötzlich um Reentrancy. Das kann man alles lernen. Klar. Aber das ist so typisch, dass ich den Lernaufwand und damit die Gefahr, etwas falsch zu machen, für zu groß halte.

Kompliziert wird es auch, wenn meine Services nicht (nur) an einer Adresse zu erreichen sind. WCF verlangt ja, dass ich die Adresse einer Dienstleistung festlege. Das finde ich starr. Reicht das starre Schema aber nicht, weil ich Mobilität oder Fehlertoleranz haben möchte, dann muss ich Klimmzüge machen oder gar orthogonal zu WCF mit Infrastruktur wie Clusterservern anfangen. Geht alles - aber könnte einfacher sein, finde ich.

Kollaboration statt Kommandoton

Schließlich: Mit WCF kann ich Nachrichten zwischen zwischen Parteien austauschen. Aber ist das Leben denn immer Nachrichtenaustausch, direkter Nachrichtenaustausch? Wer gewohnt ist, im Kommandoton zu sprechen und sofortige Ausführung erwartet, der ist mit Nachrichtenaustausch von oben nach unten in der Befehlshierarchie sicherlich zufrieden. Doch selbst das Militär hat inzwischen erkannt, dass sich mit Gehorsam allein kein Krieg gewinnen lässt. Krieg und Geschäftsleben, beide sind so dynamisch, dass autonome Entscheidungen ohne expliziten Befehl ganz vorne an der Front wichtig sind. Und Kriegsführung wie Geschäftsführung setzen daher auf Kollaboration statt Kommandoton, wenn´s darauf ankommt, wirklich etwas gebacken zu bekommen.

Kollaboration, d.h. selbstständige Zusammenarbeit an etwas Gemeinsamem, ist auch die natürlichste Arbeitsform. Dabei zwingt nicht der eine Kollaborateur den anderen, ihm - hopp! - einen Dienst zu leisten, sondern wünscht sich das sozusagen indirekt. In der Kollaboration ist Asynchronizität der vorherrschende "Antwortmodus" und Aufgaben werden "ausgeschrieben". Kollaborateure stehen um ein (mehr oder weniger handfestes) Medium herum, auf das sie gemeinsam blicken. Das kann ein Arbeitsplan sein, eine Geländekarte, eine Bauwerk, ein Tisch voll mit CRC-Cards, eine Inbox auf dem Schreibtisch oder auch ein Spielbrett. An diesem Medium arbeiten die Kollaborateure gemeinsam, damit bzw. daran teilen sie sich Aufgaben zu. Jeder behält dabei seine Autonomität, beobachtet das gemeinsame Medium, manipuliert das gemeinsame Medium. Und die von allen anerkannten Regeln, wie mit dem Medium umgegangen werden darf, sorgen dafür, dass die Kollaborateure trotz ihrer Autonomität einem gemeinsamem Ziel zustreben.

Also: Wo die Aktivitäten von autonomen Einheiten koordiniert werden sollen, geschieht das oft über einen "runden Tisch", ein gemeinsames Medium, um das sich alle versammeln. Da WCF nun eine Technologie ist, die die Zusammenarbeit von Codeeinheiten befördern will, liegt deshalb die Frage nahe, ob WCF jenseits des Kommandotons entfernter Serviceaufrufe auf die Kollaboration mittels gemeinsamen Mediums beherrscht? Die Antwort lautet nein. Für WCF ist die Arbeit an gemeinsamen Datenstrukturen kein Thema. Und genau das halte ich für ein großes Manko. Das macht WCF nämlich unintuitiv für den Einsatz in vielen Verteilungsszenarien. Schon ein simpler Chat oder ein verteiltes Spiel sind dafür gute Beispiele: Chat und Spiel (z.B. TicTacToe) sind triviale Kollaborationsaufgaben, bei denen die Beteiligten an einfachen Datenstrukturen gemeinsam arbeiten. Beim Chat ist das eine Liste von Nachrichten, beim Spiel ein zweidimensionales Array (Spielfeld). Von einer Technologie, die die Entwicklung verteilter Anwendungen erleichtern will, erwarte ich nun, dass sie mich auch unterstützt, diese natürliche Sichtweise im Code abzubilden. Das tut WCF aber nicht. Für WCF gibt es keine gemeinsame Liste, kein gemeinsames Spielfeld. WCF sagt: "Sieh zu, wie du es mit gegenseitig zugerufenen Befehlen hinbekommst, dass jeder Beteiligter denkt, es gäbe die gemeinsame Datenstruktur."

Das ist natürlich absolut legitim. Wenn WCF sich mit gemeinsamen, verteilten Datenstrukturen nicht abgeben will, dann ist das eine klare Aussage. Aber es bleibt dadurch eben auch eine Lücke. Manche oder womöglich eine ständig wachsende Zahl von Anwendungen haben es trotz WCF schwer. Bei ihnen geht es "nur" um Kollaboration und gleich eine Datenbank als gemeinsame Struktur aufzusetzen, wäre für sie Overkill. Kollaborationsinformationen sind oft nur kurzzeitig relevant.

Mit mehr Abstraktion in die Zukunft

Für mich ergibt sich damit ein "Wunschbild" wie folgt:

image

Der Stack der Kommunikationstechnologien wäschst weiter. Muss weiter wachsen. Alte Technologien werden nicht einfach ersetzt, sondern in der Relevanz nur zurückgedrängt. Es wird weiterhin Anwendungen geben, die direkt via Sockets kommunizieren müssen. Und das ist ok. Auch wird es Szenarien geben, in denen .NET Remoting Stärken gegenüber WCF ausspielt, d.h. entfernte Objekte gegenüber der  Nachrichtenorientierung einfach Abstraktionsvorteile bieten. Und warum auch nicht? Nachrichtenorientierung mit WCF wird natürlich auch ihren Platz haben. Keine Frage. Aber ich glaube, Nachrichtenorientierung tut gut daran, ihren Alleinherrschaftsanspruch über die Kommunikation in verteilten Anwendungen aufzugeben. Nachrichtenorientierung ist nicht das Gipfelkreuz auf dem Abstraktionsberg, sondern allenfalls ein Lager in großer Höhe.

Und was kommt nach bzw. oberhalb von WCF? Mein Tipp: Space Based Collaboration. Spaces sind nach 20 Jahren Forschung und kommerziellen Anläufen reif für die breite Masse. Performance und Netzwerkverfügbarkeiten sind hoch genug, um ihre Ansprüche befriedigen zu können. Abstraktion kostet ja immer etwas.

Aber Abstraktion bringt vor allem immer etwas: weniger Kopfschmerzen. Das halte ich für erstrebenswert. WCF ist gut und notwendig. Aber verteilte Anwendungen der unterschiedlichsten Art und Größe - von cross-thread Kommunikation bis global cross-platform Kommunikation - dürfen gern noch viel einfacher zu bauen sein. Spaces bieten da, meine Meinung nach, ein schönes und überfälliges Daten-/Programmiermodell. Denken in Räumen und Datenstrukturen, statt in Nachrichten und Röhren.

Tuple Spaces, JavaSpaces, GigaSpaces, SimpleDB... das ist erst der Anfang. Stay tuned!