Januar 2019

Band 34, Nummer 1

[Programmiererpraxis]

Naked-Programmierung

Von Ted Neward | Januar 2019

Ted NewardLeser, die die letzte Kolumne verpasst haben, sind vielleicht überrascht, dass ich mich nicht mehr mit dem MEAN-Stapel (Mongo, Express, Angular, Node) beschäftige. Das liegt daran, dass ich die Serie im letzten Monat abgeschlossen habe. Jetzt ist es an der Zeit, einem anderen Thema Aufmerksamkeit zu schenken.

In der MEAN-Serie habe ich den gesamten Stapel systematisch dekonstruiert und jeden seiner Bestandteile im Detail untersucht. Jetzt werde ich einen Blick auf einen Stapel (nun, eigentlich eine Technologie im Singular) werfen, der entwickelt wurde, um alle seine Teile zu einem einzigen, nahtlosen Ganzen zu verschmelzen, das dazu dienen soll, einen Großteil der erforderlichen Low-Level-Detailarbeit zu verbergen. Mit anderen Worten: Manchmal möchten Entwickler „nur mit Objekten arbeiten“, ohne sich um das Erstellen einer Benutzeroberfläche, Datenbank oder zwischengeschalteten Middleware kümmern zu müssen. In vielerlei Hinsicht ist dies der ultimative Ausdruck dessen, was Alan Kay damals in den Tagen von Smalltalk (der ursprünglichen objektorientierten Sprache von Kay) bei der „Erfindung“ von Objekten im Sinn hatte. Und es ist nur eine natürliche, logische Erweiterung des DDD-Konzepts (Domain-Driven Design) (oder, vielleicht richtiger: genau umgekehrt).

Die Ausführung von Smalltalk erfolgt immer in einer größeren Umgebung, die als Browser bezeichnet wird. Im Wesentlichen ist der Browser eine Laufzeitausführungsumgebung, eine IDE und ein Benutzeroberflächenhost, die alle zu einem Ganzen zusammengefasst werden. (Im Vergleich dazu ist ein HTML-Browser in der Regel nur ein Benutzeroberflächenhost, obwohl mehrere Anbieter – darunter Microsoft – mit Hochdruck versuchen, den HTML-Browser sowohl in eine IDE als auch in eine Ausführungsumgebung umzuwandeln). Wenn ein Entwickler eine neue Klasse in Smalltalk definiert, weiß der Browser, wie eine generische Benutzeroberfläche um ein bestimmtes Objekt herum erstellt und (abhängig von der Smalltalk-Version des jeweiligen Anbieters) wie dies in einem relationalen Speicher oder in seiner eigenen Objektdatenbank persistent gespeichert wird. Der Entwickler muss keine „Ansichten“ oder „Controller“ definieren, und „Modelle“ sind keine blutleeren reinen Datenklassen, die im Wesentlichen nur ein Datenbankschema definieren. In vielerlei Hinsicht ist dieser Ansatz im ursprünglich beabsichtigten Sinne „objektorientiert“: Entwickler interagieren mit Kunden, ermitteln die Objekte, definieren Eigenschaften für diese Objekte (und die Beziehungen zwischen ihnen), definieren Verhaltensweisen für diese Objekte und liefern das Projekt aus. Aus diesem Grund hat Kay einmal Folgendes gesagt: „Ich habe den Begriff objektorientiert erfunden, und ich kann Ihnen sagen, dass C++ nicht das ist, was ich mir darunter vorgestellt habe“. Wenn wir von Witzen auf Kosten der C++-Sprache absehen, bezog sich seine Missbilligung auf all die Tausende von Objekten, die zwischen dem Benutzer und dem eigentlichen Domänenobjekt standen, das manipuliert wurde. (Nun, er lehnte das und die ganze direkte Manipulation des Arbeitsspeichers durch Zeiger ab, aber bleiben wir beim Thema.) Was bedeutet, dass ich davon ausgehen kann, dass er von C# und Java gleichermaßen enttäuscht sein würde. (Und obendrein von Node.js.)

Natürlich haben Entwickler versucht, diesen Heiligen Gral der Objektprogrammierung wiederherzustellen, und ich werde auf einen dieser Versuche näher eingehen, der den Namen Naked Objects trägt. (Nein, ich meine es ernst, das ist tatsächlich der Name des Frameworks, der von der Idee herrührt, dass sich Entwickler ausschließlich auf den Geschäftsbereich konzentrieren und Benutzer in der Lage sein sollten, direkt „ohne zusätzliche Dekoration“ mit den Objekten zu arbeiten, wenn Sie so wollen. Oder anders ausgedrückt: Benutzer sollten mit Objekten in ihrem natürlichen, „nackten“ Zustand arbeiten können.)

Im Wesentlichen ist das, was in diesem Ansatz passiert, ebenso faszinierend wie furchteinflößend: Basierend auf Metadaten, die zur Laufzeit von einem Objekt erfasst werden (normalerweise über Reflection-Aufrufe), generieren Sie eine Benutzeroberfläche, die weiß, wie die Eigenschaften des Objekts angezeigt und bearbeitet werden können, die Bearbeitungen auf der Grundlage zusätzlicher Metadaten, die für das Objekt angegeben werden, überprüft (normalerweise über benutzerdefinierte Attribute) und die, falls erforderlich, Änderungen ablehnt, die der Überprüfung nicht standhalten. Von dort aus fragen Sie das Objekt ab und speichern es in der Datenbank (typischerweise über eine Zuordnungsschicht zwischen Objek/Relation), zusammen mit allen weiteren Objekten, die ggf. aktualisiert werden müssen, z.B. Objekte, die durch Besitz oder eine andere Beziehung verknüpft sind.

Natürlich ergibt sich der Reiz der Verwendung des Naked Objects-Frameworks auch aus den Wortspielen, die sich anbieten. Sind Sie bereit, sich den nackten Tatsachen zu stellen und in die Materie einzutauchen?

Abrufen von Naked

Starten Sie einen Browser, verweisen Sie ihn auf nakedobjects.org, und beachten Sie, dass es sich bei der Website um eine einfache Weiterleitungswebsite handelt, bei der Sie auswählen können, wohin Sie navigieren möchten (je nachdem, für welche Plattform Sie sich interessieren): Es gibt eine .NET-Variante (auf die ich meinen Fokus legen werde) und eine Java-Variante, die auch als Apache Isis bezeichnet wird. (Wieder kein Scherz – die Verantwortlichen von Isis denken darüber nach, den Namen zu ändern, aber schließlich haben sie den Namen ausgewählt, lange bevor Radikale aus dem Nahen Osten ihn in Verruf brachten.)

Wenn Sie zur .NET-Variante umgeleitet werden, gelangen Sie auf die GitHub-Projektseite für das NakedObjects Framework-Projekt, das sich zum jetzigen Zeitpunkt in Version 9 befindet. Die Projektseite hat zwei erwähnenswerte Links auf der README-Startseite: Einer davon bezieht sich auf den Entwicklerleitfaden, der beim Arbeiten mit dem Framework ein Muss ist (und ein großartiges Beispiel für gut gelungene Dokumentation), und der andere verweist auf eine ZIP-Datei mit einer Vorlagenlösung, die als Ausgangspunkt verwendet werden kann. Auch wenn die NakedObjects Framework-Assemblys (abgekürzte NOF) über NuGet verfügbar sind, ist es aus Gründen, die später deutlicher werden, im Allgemeinen einfacher, die ZIP-Vorlage zu verwenden, um Ihr neues NOF-Projekt zu starten. Rufen Sie zunächst die ZIP-Vorlage ab, extrahieren Sie diese in ein Unterverzeichnis für Code, und öffnen Sie die Projektmappendatei in Ihrer Lieblingsinstanz von Visual Studio.

Wenn Visual Studio den Ladevorgang abgeschlossen hat, werden Sie feststellen, dass die Lösung aus mehreren unterschiedlichen Projekten besteht: aus fünf, um genau zu sein. Ihre Namen sind in den meisten Fällen selbsterklärend: Template.Client ist ein Webclient, Template.Server ist der Webserver, und Template.DataBase und Template.SeedData stellen die Ebenen für die Kommunikation mit der Datenbank dar. (Im Wesentlichen sind die letzten beiden ziemlich einfache Entity Framework-Projekte, wenn Sie also EF bereits kennen, haben Sie auch den Persistenzteil von NOF im Griff.)

Im letzten Projekt der Projektmappe, Template.Model, findet die meiste, wenn nicht sogar die gesamte Entwicklerarbeit statt. Dies ist die Sammlung von Klassen, die das Domänenmodell des Projekts darstellen. Daher sollte und wird der Großteil der Aufgaben, die ein Entwickler ausführen muss, hier erledigt werden. Glücklicherweise ist in der NOF-Vorlage bereits ein wenig Beispielcode enthalten: ein Typ "Student", der eines der Exemplare darstellt, die es lieben zu studieren. Legen wir also los und schauen, was passiert. Stellen Sie sicher, dass Template.Server als Startprojekt festgelegt ist (was bereits der Fall sein sollte), drücken Sie F5, und lehnen Sie sich entspannt zurück.

Ausführen von Naked

Zunächst startet Visual Studio die Serverkomponente und benötigt aufgrund der EF-Standardkonfiguration einige Augenblicke, um die Datenbank aus dem Nichts zu erstellen. Einige Sekunden nach dem Start wird etwas JSON-Code im Browserfenster angezeigt. Dies liegt daran, dass Template.Server eigentlich ein RESTful-Server ist, was bedeutet, dass er nicht nur über HTTP funktioniert, sondern auch JSON-Code zurückgibt, der die gesamte Sammlung von Optionen beschreibt, die ein Benutzer nutzen kann, wenn er möchte. Beachten Sie, dass der JSON-Code aus etwas besteht, das im Grunde genommen wie Links aussieht: „rel“ für „relation“, „href“ für die zu verwendende URL, „type“ für die Beschreibung des erwarteten Typs usw. Auf diese Weise können Entwickler, die die generische Benutzeroberfläche (die ich als nächstes untersuche) nicht verwenden möchten, ihre eigene Benutzeroberfläche erstellen, deren Funktionsweise durch den zurückgegebenen JSON-Code festgelegt wird.

Sehen wir uns die Benutzeroberfläche an, die NOF für Sie erstellt. Navigieren Sie auf einer neuen Browserregisterkarte zu http://localhost:5001. Das Ergebnis, das zurückgegeben wird, ist... krass. Es ist eindeutig nicht auf Schönheit ausgelegt, und für das nicht damit vertraute Auge sieht es so aus, als gäbe es keinen echten Ausgangspunkt. Denken Sie jedoch daran, dass REST (wie Fielding es ursprünglich beabsichtigt hatte) und Smalltalk ähnliche Ziele hatten: eine universelle Benutzeroberfläche, sodass ein Benutzer unabhängig von der Domäne wissen würde, wie sie bedient wird. NOF erstellt die Benutzeroberfläche im Wesentlichen kollektiv aus einer Reihe von statischen Methoden von Klassen, die im Menü der obersten Ebene dieser Startseite angezeigt werden. Wenn Sie darauf klicken, werden drei Optionen verfügbar: „All Students“, „Create New Student“ und „Find Student by Name“. Es ist ziemlich offensichtlich, dass dies einfache CRUD-Methoden sind (naja, jedenfalls C und R), also lassen Sie uns sehen, was bereits im System vorhanden ist. Klicken Sie auf „All Students“, und es werden drei Studenten (die beim Start aus dem Template.SeedData-Projekt in EF eingelesen werden) angezeigt, zusammen mit einem seltsamen Symbol in der oberen rechten Ecke der zurückgegebenen Liste. Wenn Sie auf dieses Symbol klicken, werden die Ergebnisse als Tabelle und nicht nur als Liste angezeigt, aber da die Studenten nur eine FullName-Eigenschaft und nichts anderes aufweisen, ist dies noch nicht allzu interessant.

Die Auswahl eines Studenten aus dieser Liste nimmt die gesamte Seite ein. Nehmen wir an, „James Java“ hat seine Meinung geändert und wünscht eine offizielle dementsprechende Namensänderung. Wählen Sie ihn also aus der Liste aus, und wenn er angezeigt wird, wählen Sie „Edit“ aus. Beachten Sie, dass die Benutzeroberfläche geändert wird, damit sein Name bearbeitet werden kann. Ändern wir den Namen also in „James Clr“. Klicken Sie auf „Save“, und Sie befinden sich wieder in einer schreibgeschützten Benutzeroberfläche. Gehen wir zurück und sehen uns die Liste der Studenten noch einmal an. Wählen Sie das Startsymbol (das Haus in der unteren linken Ecke) aus, und Sie befinden sich wieder in diesem Startmenü. Sie könnten nach James suchen, indem Sie nochmals „Menu > All Students“ auswählen, aber das Zwischenablagesymbol zeigt eine Liste aller Objekte an, die Sie zuletzt verwendet haben. Klicken Sie darauf, und tatsächlich ist „James Clr“ vorhanden. (Der "Student" dort ist der Objekttyp, dem James zugeordnet ist. Das ist in einer Demo nicht wichtig, die nur eine Art von Objekt verwendet, aber wenn das System wächst, wachsen auch die Chancen, dass Objekte mit dem Namen „James“ sowohl ein Student als auch eine RegistrationHistory sein können.)

Studenten und das Studieren

Das Student-Modell scheint recht blutleer zu sein: Studenten sind mehr als nur ein Name! Sie studieren auch ein Fachgebiet („Subject“). Fügen wir dieses dem Modell hinzu. Beenden Sie Visual Studio, und öffnen Sie die Datei „Student.cs“ im Template.Model-Projekt. „Student“ sieht derzeit wie der in Abbildung 1 gezeigte Code aus.

Abbildung 1: Der grundlegende Student-Typ

using NakedObjects;
namespace Template.Model
{
  public class Student
  {
    // All persisted properties on a domain object must be 'virtual'
    NakedObjectsIgnore] // Indicates that this property
                        // will never be seen in the UI
    public virtual int Id { get; set; }
    [Title]// This property will be used for the object's title at
           // the top of the view and in a link
    public virtual string FullName { get; set; }
  }
}

Fügen Sie „Student“ eine neue Eigenschaft hinzu, beispielsweise „Subject“ (ebenfalls eine Zeichenfolge sowie öffentlich und virtuell), und drücken Sie dann erneut F5. Durch die Entwicklungsstandardeinstellungen in EF wird James Java seine Namensänderung verlieren, aber beachten Sie, was Sie gewonnen haben: In der Benutzeroberfläche und in der Datenbank verfügen Sie nun über Studenten, die Fachgebiete haben. Sie sind zurzeit noch alle leer, aber andererseits haben viele Studenten auch keine Ahnung, was sie studieren. Das schwerer wiegende Argument ist, dass Sie mit dieser einzigen Eigenschaft eine vollständige Benutzeroberflächenunterstützung sowie Datenbankunterstützung erhalten haben, ohne dass Sie Code schreiben müssen, um die Benutzeroberfläche zu erstellen, die Eingabe zu überprüfen oder die Daten persistent zu speichern.

Zusammenfassung

Hier gibt es offensichtlich jede Menge Aspekte, die ich gerade übersprungen habe, und es wäre reizvoll, diese näher zu untersuchen. Also werde ich mich in einigen weiteren Artikeln mit NOF beschäftigen und auch auf seine Einschränkungen eingehen. Der wichtige Punkt ist, dass insbesondere bei nicht konsumentenorientierten Anwendungen nicht für alles eine handgefertigte, künstlerisch wertvolle Benutzeroberfläche und Datenbank verwendet werden muss. Manchmal ist die Geschwindigkeit, mit der eine Anwendung generiert werden kann, weitaus wichtiger als ihre Schönheit. NOF und andere von DDD inspirierte Tools können genau das sein, was der Arzt in solchen Situationen verordnen würde, und Sie haben sogar einige Möglichkeiten, die Dinge „schöner“ zu machen, indem Sie ein angepassteres Angular-Front-End (oder anderes SPA-Framework) erstellen. Nächstes Mal werde ich einige der Optionen und Funktionen von Domänenklassen in NOF untersuchen, und wir werden sehen, wie gut NOF mit häufigen Problemen der Benutzeroberfläche umgehen kann. Bis dahin: 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.