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.
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.