Juli 2019

Band 34, Nummer 7

[Programmiererpraxis]

Naked-Programmierung: Naked-Netzwerke

Von Ted Neward | Juli 2019

Ted NewardWillkommen zurück, Freunde des NOF. Letztes Mal habe ich mich mit NakedObjects-Aktionen beschäftigt, die die Geschäftslogik für ein bestimmtes Geschäftsobjekt in einer Methode erfassen, die das NOF-Framework dem Benutzer zur direkten Bearbeitung und Verwendung zur Verfügung stellt. Bis zu einem gewissen Grad möchte ich diese Untersuchung fortsetzen, da im NOF Angular-Client der Aufruf einer Aktion im Client irgendwie auf den Server gelangt, von wo aus Änderungen in die Datenbank geschrieben werden können. Irgendwie und irgendwo erfolgt eine Netzwerküberquerung, um vom Client zum Server zu gelangen, und es ist wichtig, diesen Vorgang zu untersuchen, damit er nicht unter dem ganzen Hype begraben wird.

Auf die Gefahr hin, Sie mit noch einem weiteren Wortspiel rund um optionale Kleidung zu langweilen: Sind Sie bereit für Naked-Netzwerke?

Echt RESTmäßig

Um den NOF Restful-API-Netzwerkstandard bzw. das -protokoll zu verstehen, müssen Sie sich zunächst mit einigen Schlüsselkonzepten vertraut machen. Ich möchte mich mit REST beschäftigen, aber nicht mit dem REST, das gewöhnlich von Architekten und dem Marketing von Hype Machines auf leichtfertige Weise verwendet wird. Ich muss zum Ursprung von REST zurückkehren und das Quellmaterial untersuchen.

Im Jahr 2000, als Roy Fielding die Doktorarbeit veröffentlichte, die als Geburtsstätte von REST gilt, wurde eine neue Netzwerkbewegung ins Leben gerufen. Um fair zu sein, wäre es jedoch genauer zu sagen, dass ein vorhandener Netzwerkansatz seziert und beschrieben wurde. Die Dissertation von Fielding ist eine meisterhafte Studie über den Entwurf verteilter Systeme und wird jedem, der verstehen möchte, wie verteilte Systeme effektiver erstellt werden können, unbedingt als Lesestoff empfohlen. Der Teil, mit dem sich die meisten Menschen beschäftigen, ist in Kapitel 5 des Dokuments mit dem Titel „Representational State Transfer (REST)“ enthalten. (Die gesamte Dissertation ist unter bit.ly/1NbHM8Y verfügbar. Wenn Sie es vorziehen, können Sie auch direkt zu Kapitel 5 unter bit.ly/1eTY8AI navigieren.)

Leser, für die Fieldings Dissertation neu ist, werden Kapitel 5 besonders interessant finden (obwohl ehrlich gesagt das gesamte Dokument interessant und definitiv lesenswert ist), weil Fielding bewusst den REST-Architekturstil von Grund auf „aufbaut“ (und er ist sich hier ganz bewusst über die Terminologie im Klaren), beginnend mit dem, was er als Nullstil bezeichnet: „Der Nullstil beschreibt ein System, in dem es keine erkennbaren Grenzen zwischen Komponenten gibt.“ Er arbeitet sich langsam durch eine Reihe anderer Stile durch und bemerkt, dass es in jedem Fall ein Element des Stils gibt, das für den Aufbau des World Wide Web nützlich ist – was die Fallstudie für REST ist.

Den Kernbereich des Dokuments, auf den Sie sich konzentrieren sollten, finden Sie in Abschnitt 5.1.5: „Uniform Interface“ (Einheitliche Schnittstelle). Ich zitiere hier den Absatz in seiner Gesamtheit (Originaltext in englischer Sprache):

Das zentrale Merkmal, das den REST-Architekturstil von anderen netzwerkbasierten Stilen unterscheidet, ist die Betonung einer einheitlichen Schnittstelle zwischen den Komponenten. Durch die Anwendung des Softwareengineeringprinzips der Allgemeingültigkeit auf die Komponentenschnittstelle wird die gesamte Systemarchitektur vereinfacht und die Sichtbarkeit von Interaktionen verbessert. Implementierungen sind von den von ihnen bereitgestellten Diensten entkoppelt, was eine unabhängige Entwicklungsfähigkeit fördert. Der Nachteil ist jedoch, dass eine einheitliche Schnittstelle die Effizienz beeinträchtigt, da die Informationen in standardisierter und nicht in anwendungsspezifischer Form übertragen werden. Die REST-Schnittstelle ist so konzipiert, dass sie für die grobkörnige Hypermedia-Datenübertragung effizient und für den allgemeinen Fall des Webs optimiert ist, aber zu einer Schnittstelle führt, die für andere Formen der architektonischen Interaktion nicht optimal ist. Um eine einheitliche Schnittstelle zu erhalten, sind mehrere architektonische Einschränkungen erforderlich, um das Verhalten der Komponenten zu steuern. REST wird durch vier Schnittstellenbeschränkungen definiert: Identifizierung von Ressourcen, Manipulation von Ressourcen durch Darstellungen, selbstbeschreibende Nachrichten und Hypermedia als Engine des Anwendungszustands.

Hier entfaltet sich eine ziemlich große Menge an Konzepten, die verstanden werden müssen, aber insbesondere der letzte Satz liefert den Schlüssel zum Verständnis der NOF Restful-API: „Hypermedia als Engine des Anwendungszustands“ bedeutet, dass der gesamte Zustand der Netzwerkinteraktion in einem Hypermediadokument gespeichert ist, das vom Client und vom Server gemeinsam verwendet wird. In traditionellen Webszenarien besteht dieses Hypermediadokument aus HTML-Text, der an den Client zurückgesendet wird, ohne weitere Spuren der Clientidentität auf dem Server zu hinterlassen, was wiederum ermöglicht, dass der Server in Bezug auf den Client völlig zustandslos ist. (Aus diesem Grund der Zustandslosigkeit beschließt Fielding übrigens, das Konzept von Cookies als Clientbezeichner auf dem Server zu ignorieren. Tatsächlich ignorieren sowohl Fielding als auch die HTTP-Standards Cookies vollständig.)

Wenn sich eine Netzwerkinteraktion als „RESTful“ charakterisieren lassen soll, bedeutet dies in der Praxis, dass sie diesem Prinzip der „einheitlichen Schnittstelle“ folgen und alle Zustände in Hypermedia erfassen muss, d.h. in einem Dokumentformat, das die vom Client erlaubten „nächsten Schritte“ enthält: ein Dokument, das zwischen Client und Server ausgetauscht wird.

(Nehmen Sie übrigens zur Kenntnis, dass Fielding deutlich gemacht hat, dass REST nicht immer überlegen ist: „Die REST-Schnittstelle ist so konzipiert, dass sie für die grobkörnige Hypermedia-Datenübertragung effizient ist..., aber zu einer Schnittstelle führt, die für andere Formen der architektonischen Interaktion nicht optimal ist.“ Sie werden Fieldings Gefühle nicht verletzen, wenn Sie etwas anderes als REST für Ihr nächstes Projekt verwenden.)

RESTful-API

Die NOF Restful-API, die in der Dissertation von Fielding behandelt wird, beschreibt ein HTTP-basiertes Protokoll, das REST-Prinzipien mit all ihren Vor- und Nachteilen umfassen soll. Insbesondere schränkt die Restful-API ihre gesamte Kommunikation um „Hypermedia als Engine des Anwendungszustands“ (Hypermedia-As-The-Engine-Of-Application-State) ein (von REST-Nutzern HATEOAS genannt und vom Autor meines persönlichen Blogs zum „schlechtesten Akronym aller Zeiten“ gewählt), sodass jeder Austausch von einem NakedObjects-Client in einer vollständigen Hypermediaanforderung durchgeführt wird und zu einem vollständigen Hypermediadokumentergebnis führt. Der einfachste Weg ist natürlich, diesen Vorgang in Aktion zu sehen. Wenn also das NOF Conference-Projekt nicht bereits auf Ihrem Computer ausgeführt wird, starten Sie es. Anstatt den Browser auf localhost:5001 zu verweisen (um das Angular-Projekt in Ihren Browser herunterzuladen), verweisen Sie dieses Mal stattdessen auf localhost:5000, also den Port, an dem der Server auf Restful-API-Anforderungen vom Browser lauscht.

Die ursprüngliche Anforderung (http://localhost:5000) ergibt das in Abbildung1 gezeigte JSON-basierte Ergebnis.

Abbildung 1: Die anfängliche Hypermediaanforderung

{
  "links":[
  {
    "rel":"self",
    "method":"GET",
    "type":"application/json;
      profile=\"urn:org.restfulobjects:repr-types/homepage\"; charset=utf-8",
    "href":"http://localhost:5000/"
  },
  {
    "rel":"urn:org.restfulobjects:rels/user",
    "method":"GET",
    "type":"application/json; profile=\"urn:org.restfulobjects:repr-types/user\";
      charset=utf-8",
    "href":"http://localhost:5000/user"
  },
  {
    "rel":"urn:org.restfulobjects:rels/services",
    "method":"GET",
    "type":"application/json; profile=\"urn:org.restfulobjects:repr-types/list\";
      charset=utf-8; x-ro-element-type=\"System.Object\"",
    "href":"http://localhost:5000/services"
  },
  {
    "rel":"urn:org.restfulobjects:rels/menus",
    "method":"GET",
    "type":"application/json; profile=\"urn:org.restfulobjects:repr-types/list\";
      charset=utf-8; x-ro-element-type=\"System.Object\"",
    "href":http://localhost:5000/menus
  },
  {
    "rel":"urn:org.restfulobjects:rels/version",
    "method":"GET",
    "type":"application/json; profile=\"urn:org.restfulobjects:repr-types/version\";
      charset=utf-8",
    "href":http://localhost:5000/version
  }],
  "extensions":{}
}

Das ist ziemlich viel Kauderwelsch, zumindest bis der Datenstrom entpackt wird. Beachten Sie jedoch die Struktur, die bereits offensichtlich ist: Es handelt sich um ein JSON-Dokument, bestehend aus einem Stammobjekt mit zwei Feldern: „Links“ und „Extensions“. Letzteres Feld ist leer, aber das erste Feld ist ein Array aus „rel“/„method“/„type“/„href“-Feldern (in diesem Fall fünf von ihnen), alles GET-Anforderungen, wobei das „href“-Feld genau das bereitstellt, wonach es klingt: einen Linkverweis.

Probieren wir einen der einfacheren Links aus (den letzten aufgelisteten), der „version“ im Link aufweist. Wenn Sie dies in die Adressleiste des Browsers einfügen, erhalten Sie das in Abbildung2 gezeigte Ergebnis.

Abbildung 2A: Ein einfacher Link

{
  "specVersion":"1.1",
  "implVersion":"8.1.1\r\n",
  "links":[
    {
      "rel":"self",
      "method":"GET",
      "type":"application/json;
        profile=\"urn:org.restfulobjects:repr-types/version\";
        charset=utf-8",
      "href":http://localhost:5000/version
    },
    {
      "rel":"up",
      "method":"GET",
      "type":"application/json;
        profile=\"urn:org.restfulobjects:repr-types/homepage\";
        charset=utf-8",
      "href":http://localhost:5000/
    }
  ],
  "extensions":{},
  "optionalCapabilities":{
    "protoPersistentObjects":"yes",
    "deleteObjects":"no",
    "validateOnly":"yes",
    "domainModel":"simple",
    "blobsClobs":"attachments",
    "inlinedMemberRepresentations":"yes"
  }
}

Natürlich geht es ebenso weiter: Dieses Mal enthält das Objekt auf oberster Ebene „specVersion“ und „implVersion“ als Versionen der Restful-Objektspezifikation sowie das Array „links“, das Sie bereits zuvor gesehen haben (zusammen mit einigen anderen Feldern, die für diese Kolumne nicht relevant sind).

Wenn Sie hingegen zu dem in der ersten Anforderung (http://localhost:5000/user) genannten Link „user“ navigieren, erhalten Sie das, was in Abbildung 3 gezeigt wird.

Abbildung 3: Ergebnisse aus dem Link „user“

{
  "links":[
    {
      "rel":"self",
      "method":"GET",
      "type":"application/json; profile=\"urn:org.restfulobjects:repr-types/user\";
        charset=utf-8",
      "href":"http://localhost:5000/user"
    },
    {
      "rel":"up",
      "method":"GET",
      "type":"application/json;
        profile=\"urn:org.restfulobjects:repr-types/homepage\";
        charset=utf-8",
      "href":"http://localhost:5000/"
    }
  ],
  "extensions":{},
  "userName":"",
  "roles":[]
}

Dies stellt das inzwischen vertraute „Links“-Array sowie „userName“ und „roles“ zur Verfügung.

Um zu interessanten Objekten (z.B. meinen Referenten) in der Angular-Anwendung zu gelangen, kann ich das Menü durchsuchen, das auf der Homepage angezeigt wird. Für die Restful-API bedeutet dies, dass ich den Link „menu“ von der Homepage überprüfen muss, um die Optionen anzuzeigen. Innerhalb dieses zurückgegebenen JSON-Codes (den ich hier weglasse, um in dieser Kolumne keinen Platz für weitere unformatierte JSON-Ausgaben zu verschwenden) erhalte ich ein „value“-Array, das aus mehreren Objekten besteht, die jeweils einen „title“ (den Menüelementtext) aufweisen (wie „Speakers“ und „Talks“) sowie ein entsprechendes „href“-Element, das Links zum SpeakerRepository bzw. zum TalkRepository bereitstellt. Es überrascht nicht, dass diese Links wiederum Links zu den von diesen Diensten angebotenen Aktionen (jeweils innerhalb eines eigenen Untermenüs) enthalten.

Kurz gesagt, stellt die Restful-API genau das bereit, was Fielding ursprünglich in seinem REST-Kapitel beschrieben hat: Hypermedia (in diesem Fall in Form von JSON-Dokumenten mit eingebetteten Links) als Engine des Anwendungszustands. Näher kommen Sie an REST nicht heran, ohne einen eigenen Browser zu erstellen. (Was technisch gesehen – wenn man darüber nachdenkt – genau das ist, was ein Naked Objects-Client ist: ein Browser, der für die Interaktion mit Domänenobjekten anstelle von HTML entwickelt wurde.)

Die Restful-API ist übrigens nicht der erste Fall, bei dem diese Art von Interaktion behandelt wird. Die von Microsoft entwickelte OData-Spezifikation war ein weiterer solcher Ansatz, der (leider) unter den Nicht-Microsoft-Plattformen nicht standhielt. Aber bereits vorher beschäftigten sich zahlreiche Experten damit, wie diese Art von Interaktion mit JSON oder RSS XML realisiert werden kann.

Einer der klaren Vorteile dieses Ansatzes liegt im Testen: Um einen bestimmten Endpunkt zu testen, müssen Sie, wenn der gesamte Dienst zustandslos ist, nur die ordnungsgemäß zugewiesene und parametrisierte Anforderung senden, und der Server sollte mit der richtigen Antwort antworten. In einigen Fällen (insbesondere für diejenigen Dienste, die hinter einem Autorisierungswall bleiben müssen) kann dies einen zusätzlichen Anforderungs-/Antwortzyklus erfordern. Aber dieser Ansatz birgt sicherlich noch immer Vorteile verglichen mit der tief geschachtelten Reihe von Aufrufen, die eine HTTP-API im RPC-Stil normalerweise mit sich bringt.

Zusammenfassung

Es gibt noch eine Reihe weiterer interessanter Konzepte im Naked Objects Framework, aber das gilt für fast jedes Thema, das in dieser Kolumne jemals behandelt wurde, und es ist an der Zeit, nach vorne zu schauen. Denken Sie daran, dass der Sinn dieser Serie nicht darin besteht, Sie zu überreden, NOF in Ihren eigenen Projekten einzusetzen (obwohl ich diese Idee von ganzem Herzen unterstütze, wenn die Umstände es begünstigen), sondern dass Sie darüber nachdenken sollten, wie Sie einige dieser Konzepte in Ihren eigenen benutzerdefinierten Projekten verwenden könnten. Naked-Objekte sind (wie Sie bereits gesehen haben) der ultimative Ausdruck des Domänenobjektkonzepts, und wenn Ihr Projekt den Zustand einer allgegenwärtigen Sprache erreicht hat und die Domänenobjekte eindeutig identifizieren kann, aber eine gewisse Fluktuation und Veränderung im Laufe der Zeit erwartet, während das Unternehmen wächst und sich entwickelt, könnte es nützlich sein, ein Mini-NOF-Framework zur Anzeige und Bearbeitung dieser Objekte zu erstellen. Ebenso ist es fast unmöglich, eine inkonsistente Benutzeroberfläche bereitzustellen, wenn die Benutzeroberfläche während der Laufzeit durch die Untersuchung von Objekten spontan generiert wird. Und lassen Sie uns erst gar nicht über die Versionsverwaltung sprechen: Ein einzelner Client, der weiß, wie er Objekte basierend auf ihren Laufzeiteigenschaften anzeigt und bearbeitet, ist ein starker Beweis dafür, dass nicht jedes Mal eine neue Clientversion eingeführt werden muss, wenn sich die Eigenschaften oder Aktionen eines Domänenobjekts als Reaktion auf Geschäftsanforderungen ändern.

Egal, ob Sie sie lieben oder hassen: Naked Objects sind ein mächtiges Tool in Ihrer Werkzeugsammlung und etwas, mit dem sich jeder Entwickler einige Zeit lang beschäftigen sollte, bevor er einen anderen Ansatz wählt.

Apropos: Es ist höchste Zeit, dass auch wir nach vorne schauen. Ich wünsche Ihnen viel Spaß beim Programmieren!


Ted Neward ist ein in Seattle ansässiger Berater, Redner und Mentor für zahlreiche Technologien. Er hat unzählige Artikel geschrieben und als Autor und Mitautor ein Dutzend Bücher verfasst. Er hält weltweit Vorträge. Sie erreichen ihn unter ted@tedneward.com, oder lesen Sie seinen Blog unter blogs.tedneward.com.

Unser Dank gilt dem folgenden technischen Experten für die Durchsicht dieses Artikels: Richard Pawson


Diesen Artikel im MSDN Magazine-Forum diskutieren