Gestern abend bin ich zufällig über eins der Sub-Projekte von Spring gestolpert: Spring-WS (Spring WebServices). Beim Lesen der Dokumentation stach mir die Behauptung ins Auge "Best Practice made easier", gemeint ist ein Contract-First Ansatz und das Arbeiten direkt mit den XML-Nachrichten.
In einem eigenen Abschnitt wird ausgeführt, warum (speziell im Falle von WebServices) der Contract-First Ansatz der Bessere ist:
Zum einen lassen die Type-Definitionen mit XML Schema Konstruktionen zu, die in Java (um diese Sprache geht es hier ;-)) gar nicht möglich sind.
Zum anderen lassen bestimmte Sprachkonstrukte, wie zyklische Bezüge nicht einfach so nach XML abbilden.
Deshalb, so die Schlussfolgerung, sei es das Beste, direkt mit den XML-Nachrichten zu arbeiten. Hierfür gibt’s ja schließlich eine Reihe von APIs mit denen sich das einfach bewerkstelligen läßt.
Als krönender Abschluss wird, im Falle einer neuen Version des Contracts und damit anderer XML-Nachrichten, auf die Möglichkeit verwiesen, diese unter Umständen ganz einfach mit XSLT wieder auf die "Old-Style"-Nachricht abzubilden, und somit müßte man nicht mal eine neue Java-Implementierung schreiben.
Geht’s noch …
In der Tat, um mal beim letzten Punkt anzufangen, man braucht keine neue Java-Implementierung und auch kein neues Java-Interface, aber dafür ein XSLT-Stylesheet. Und wenn das dann nicht so arbeitet, wie man gedacht hat, dann baucht man einen Debugger für die Transformation-Engine, damit man sieht wo es schief geht ….
WebServices als einfache Middleware
Man kann WebServices auch anders sehen: nämlich als eine weitere Möglichkeit verteiltes Rechnen (am besten über System- und Sprachgrenzen hinaus) zu ermöglichen. Dieser Anspruch wird ja auch immer wieder propagiert. Wenn das allerdings der Anspruch sein soll, dann bin ich als System-Designer oder auch als Application-Developer reichlich wenig daran interressiert, wie das Wire-Protokoll meiner Middleware funktioniert. Oder interessiert sich irgendjemand so genau wie Java RMI auf der Leitung funktioniert, oder wie sich (früher) ein Corba-Client per IIOP mit seinem Server unterhalten hat?
Das interessiert keinen Menschen, weil es niemand interessieren muß! Man benutzt es einfach. Es gibt klare Regeln welche Typen wie auf der Leitung zu kodieren sind und es gibt darüber hinaus ein (einigermassen) eindeutig definierten Sprachmapping, das die möglichen Konstrukte eindeutig in die unterschiedlichen Sprachen abbildet.
XSD als Typbeschreibung
Wenn also XML Schema so schwierig in ein Sprachmapping zu überführen ist, dann sollte man es am besten einfach gar nicht verwenden! Oder so weit einschränken, dass bestimmte Konstruktionen wie die bei Spring WS angeführten "Restrictions" von Basistypen eben im Kontext von WebServices nicht erlaubt sind.
Auch sind bestimmte Regeln die sich mit XML Schema konstruieren lassen im Rahmen einer Schema Types Definition in der Interfacebeschreibung eines WebServices eh am falschen Platz.
Contract ist nicht nur die technische Interfacebeschreibung
Der Contract (also Vertrag) geht sowieso immer über die rein technische Beschreibung der Schnittstelle hinaus. In einem Vertrag muss man vielmehr auch die Rahmenbedigungen oder Spielregeln bekannt geben, wie man die Schnittstelle richtig benutzt. Was nutzt einem da eine Werteeinschränkung von z.B. 1 – 10 bei einem bestimmten Parameter einer Operation, wenn sich das nur im Schema und im Fehlerfall in einem Validierungfehler ausdrückt? Nicht viel oder eigentlich gar nichts. Der die Schnittstelle benutzt wird dem Integer nicht ansehen, dass eine Einschränkung des Wertebereichs vorliegt. Sperrt man den Interger in eine Klasse ein, die den Wertebereich prüft / erzwingt ist auch nicht viel gewonnen, das ist in der Praxis viel zu umständlich.
Besser es steht in der Dokumentation der Schnittstelle eben dabei, dass dieser Parameter diese und jene Semantik hat und deshalb in seinem Wertbereich eingeschränkt ist. Eine Prüfung nimmt dabei auch besser die Businesslogik vor, schließlich könnte es ja sein, dass diese auch von nicht Schems gecheckten WS-Clients gerufen wird. Die Businesslogik kann im Fehlerfall auch gleich eine aussagekräftige Fehlermeldung erzeugen, die beim Aufrufer allemal mehr Information hinterläßt als ein Schemavalidierungfehler.
Interoperable WebServices
Wenn also der Anspruch von WebService ist möglichst interoperabel zu sein und es dazu ja sogar eigene Standards gibt, die WebServices interoperabler machen (WS-I Basic Profile), dann sollte das IMHO aber funktionieren ohne das ich mich mit den XML-Nachrichten herumschlagen muss.
Contract first!
Damit ich nicht missverstanden werde, ich bin von jeher ein überzeugter Vertreter des "Contract first" Ansatzes. Zu Zeiten als es noch keine WebServices gab, war das aber auch viel einfacher: da gab es eine richtige Sprache, um technische Interfacebeschreibungen zu definieren. Diese Sprache las sich wie C++ oder Java war also von den meisten Techniker relativ leicht zu verstehen. Man konnte in dieser Sprache auch gleich die Dokumetation (wie bei JavaDoc) unterbringen und so neben der technischen auch eine semantische Beschreibung mitliefern. Man brauchte auch nicht unbedingt ein Werkzeug (ausser einem Editor) um selbst komplexe Interfaces zu definieren. Das Wunderding heisst: IDL.
Ich kann mich nicht erinnern, dass ich auch nur ein Interface im Corba-Umfeld nicht mit der IDL begonnen hätte. Eben Contract first! Und machen wir das mit XML Schema und WSDL, und dann bauen wir Implementierungen, die mit XPath-Expressions auf den XML Nachrichten "herumoperieren" und diese zuvor noch mit XSLT transformieren …
Sorry ist ein bisschen lang geworden, aber ich musste mich mal auslassen … 😉