Aus Linux-Magazin 07/2013

Domain-Driven Design mit Apache Isis

© Luca Bertolli, 123RF.com

Trotz vieler Fortschritte in der Software-Entwicklung gerät die fachliche Aufgabenstellung oft aus dem Blick. Das Framework Apache Isis möchte mit einem alternativen Vorgehen Abhilfe schaffen: Es stellt ein Modell der fachlichen Domäne ins Zentrum und generiert daraus die Anwendung.

Die Entwicklung von Software ist komplex. Doch sowohl auf Architektur- als auch auf Entwicklungsebene existieren Mittel, um dieser Herausforderung zu begegnen. J2EE war mit seinen Mustern und mehrschichtigen Architekturen jedoch eher ein Negativbeispiel für viel unnötige Komplexität. Das vom Entwickler Eric Evans beschriebene Domain-Driven Design (DDD, [1]) dagegen lenkt den Fokus der Umsetzung weg von der konkreten Technologie und hin auf die fachliche Domäne und ihre Objekte.

Frameworks wie Grails lehnen sich an DDD an und ergänzen es um den Ansatz “Convention over Configuration”, sodass sich eine komplette Anwendung aus einem im Code definierten Domänenmodell generieren lässt. Ein Vorteil dieses Ansatzes ist die klare Trennung der Zuständigkeit zwischen Technik und Fachlichkeit.

Außerdem umgeht DDD die bei einer Schichtenarchitektur leider nicht vermeidbare Umwandlung der Objekte in die von der jeweiligen Schicht benötigten Formate (Abbildung 1). Selbst einfache Änderungen muss der Entwickler dabei mehrfach vornehmen, was in der aus dem Domänenmodell erzeugten Anwendung nur an einer Stelle erforderlich ist. Insofern bedeutet weniger Code nicht nur bessere Lesbarkeit und Verständlichkeit, sondern auch weniger Anpassungs- und Pflegeaufwand.

Abbildung 1: Unterschiedlicher Pflegeaufwand: Schichten-Architektur (links) im Vergleich mit dem Domänenmodell von Apache Isis (rechts).

Abbildung 1: Unterschiedlicher Pflegeaufwand: Schichten-Architektur (links) im Vergleich mit dem Domänenmodell von Apache Isis (rechts).

Nackte Objekte

Das Framework Apache Isis erzeugt aus dem Domänenmodell den Code für eine komplette Anwendung inklusive Front- und Backend. Der Entwickler beschreibt die Geschäftslogik lediglich im Domänenmodell, das Framework erzeugt eine nutzbare Oberfläche.

Der Consultant Dan Haywood [2] hat dazu 2010 das Naked-Objects-Muster (siehe Kasten “Naked Objects”) mit dem REST-Ansatz kombiniert und in Isis neu implementiert. Parallel dazu hat er die REST-ful Objects Specification [3] erstellt, die inzwischen in Version 1.0 verfügbar ist und ein generisches REST-ful-Hypermedia-API beschreibt. Dieser Ansatz ist auch unter der Abkürzung Hateoas (Hypertext as the Engine of Application State) bekannt.

Naked Objects

Etwa zur gleichen Zeit wie Evans DDD präsentierte Richard Pawson in seiner Doktorarbeit [5] das Naked-Objects-Muster [6], das sowohl für C# als auch für Java umgesetzt ist. Auch dieser Ansatz generiert aus dem Fachdomänenmodell zur Laufzeit eine komplett funktionsfähige Anwendung mit Oberfläche und Datenbanktabellen. Naked Objects eignet sich gut dazu, rasch Oberflächen-Prototypen zu erstellen und das Objektmodell fachlich zu validieren.

Statt der immer noch weitverbreiteten Schichtenarchitektur verwendete Naked Objects eine Port-Adapter-Architektur, die Abbildung 2 schematisch darstellt. Ein Port entspricht einer Steckdose, in die sich unterschiedliche Geräte einstecken lassen, sofern sie die erforderliche Schnittstellenbeschreibung erfüllen. Statt einer SQL-Datenbank kann der Entwickler deshalb auch einfach per Konfiguration eine NoSQL-Datenbank oder statt eines XHTML-Viewers einen Viewer mit dem Webframework Wicket erzeugen und verwenden. Dadurch ist das Domänenmodell von seinen Diensten entkoppelt und lässt sich über weitere zusätzliche Adapter leicht erweitern.

Abbildung 2: Die Port-Adapter-Architektur erleichtert das Erweitern des Domänenmodells um Dienste.

Abbildung 2: Die Port-Adapter-Architektur erleichtert das Erweitern des Domänenmodells um Dienste.

Allein der Blick auf die 220 Seiten lange Spezifikation zeigt, dass das API weit über die naive Umsetzung der Standard-HTTP-Methoden (»GET« , »POST« , »PUT« , »DELETE« ), URI-Konventionen und ein wenig Content Negotiation in einem einfachen REST-basierten Ansatz hinausgeht. Diese Spezifikation ist inzwischen für Server und Client in mehreren Programmiersprachen umgesetzt. Isis ist ihre Referenzimplementierung in Java.

Selbstbeschreibend

Die meisten Ähnlichkeiten hat REST-ful Objects mit dem von Microsoft imitierten Odata-Standard. Konzentriert sich Odata ausschließlich auf die CRUD-Operationen (Create, Read, Update und Delete), können mit REST-ful Objects auch weitere Aktionen auf den Objekten aufgerufen werden, ohne gleich das gesamte Datenmodell zu veröffentlichen.

Darüber hinaus setzt REST-ful Objects auch das REST-ful-Prinzip um, dass jeder REST-Aufruf in seiner Antwort Informationen gibt, über welche URLs der Aufrufer weiter verfahren kann. Damit sind die von REST-ful-Anwendungen angebotenen Dienste selbstbeschreibend – der Client braucht lediglich den Einstiegspunkt zu kennen, aber nicht alle vorhandenen Dienste mit ihrer Semantik.

Seit 2012 ist Isis ein vollwertiges Projekt der Apache Software Foundation und hat mehrere Releases erlebt. Das Framework bietet für die Oberfläche Viewer für Webframeworks wie Apache Wicket, Scimpi, Jquery oder REST-easy REST-ful. Zum Speichern der Daten über das JDO-Persistenzframework Datanucleus eignen sich verschiedene NoSQL- und SQL-Datenbanken. Isis bietet standardmäßig Authentifizierungs- und Autorisierungsdienste auf Basis von Shiro an. Die dafür benötigen Daten lassen sich entweder im Dateisystem, einer Datenbank oder in einem LDAP-System ablegen.

Apache Isis kommt für Rapid Prototyping [4] oder zum Evaluieren des Domänenmodells zum Einsatz. Daneben kann es automatisch eine vollständige Anwendung daraus generieren. Alternativ kann der Anwender auch über REST-ful-Webservices ohne eine Oberfläche auf die Domänenobjekte zugreifen. Im Extremfall erstellt der Entwickler sogar nur das reine Domänenmodell, indem er mit seinen Objekten das »DomainObjectContainer« -Interface implementiert.

Praktisches

Wer sich einen ersten Eindruck von Isis verschaffen möchte, ruft entweder die Online-Demo-Anwendung in der veralteten Version 0.2 unter [7] auf oder installiert selbst das Archiv »isis-onlinedemo.war« in einen lokalen Tomcat-Server. Das Codebeispiel stellt eine To-do-Listen-Verarbeitung dar und ist unter [8] beschrieben. Das Domänenmodell besteht aus der Entität »ToDoItem« und ihrem Repository »ToDoItems« . Das Repository kümmert sich mit seinen Factory-Methoden um die Erzeugung und den Lebenszyklus der Objekte.

Eine Besonderheit von Isis ist, dass der Programmierer im Domänenmodell nicht nur die Attribute und ihre Aktionen mit Validierungsregeln (»@RegEx« ) beschreiben kann, sondern dort auch angeben darf, in welcher Form und Reihenfolge (»@MemberOrder« ) das Framework diese anzeigt.

Los geht’s

Für den Build der Anwendung sind JDK 7 und Maven 3 nötig. Der Maven-Archetyp »quickstart_wicket_restful_jdo-archetype« erleichtert das lästige initiale Projekt-Setup. Wie der Name des Archetyps signalisiert, erzeugt er aus dem Domänenmodell eine JDO-Persistenzschicht und als Oberfläche sowohl REST-Dienste als auch eine Oberfläche mit dem Webframework Wicket. Als Datenbank dient Hsql DB.

Da Test-Driven Development ein wichtiges Element agiler Entwicklung und ein Ziel von Isis ist, bietet das Framework mit dem einheitlichen Domänenmodell gute Unterstützung dafür, daneben Testfälle in Junit und Test-Stories sowie Testszenarios für Concordion, ein Framework für Behaviour-Driven Design (BDD).

Der Maven-Aufruf in Listing 1 erzeugt das Verzeichnis »myapp« mit den Dateien der Anwendung. Die dabei auftauchenden Fragen darf der Benutzer mit den vorgeschlagenen Standardwerten beantworten. Danach wechselt er in das Verzeichnis und kompiliert mit »mvn install« die generierten Quelltexte. Anschließend lässt sich mit dem Kommando

Listing 1

Maven-Aufruf

01 mvn archetype:generate -D archetypeGroupId=org.apache.isis.archetype -D archetypeArtifactId=quickstart_wicket_restful_jdo-archetype -D archetypeVersion=1.0.2 -D groupId=de.materna -D artifactId=myapp
mvn antrun:run

die Anwendung samt dem integrierten Webserver Jetty starten. Alternativ kann man das erzeugte WAR-Archiv in einen anderen Webcontainer wie etwa Tomcat installieren.

Unter »http://localhost:8080« lässt sich die Startseite der Anwendung im Browser aufrufen. Ein REST-Client kann sich mit »http://localhost:8080/restful/« verbinden, ein menschlicher Anwender sieht sich lieber unter »http://localhost:8080/wicket/« die Weboberfläche an.

Dort meldet er sich mit dem Benutzer »sven« und dem Passwort »pass« an, wonach die Menüs der Domänenobjekte »ToDos« , »Fixtures« und »Audit Service Demo« zu sehen sind. Hier erstellt der Anwender mit »Fixtures install« die ersten Arbeitsaufträge mit Testdaten. Diese kann er in der Arbeitsliste bearbeiten und die darauf möglichen Aktionen durchführen. Zusätzlich gibt es die Möglichkeit, sich unter »http://localhost:8080/restful/services« mit einfachen HTTP-Operationen schrittweise durch das Domänenmodell zu klicken.

Tabelle 1 führt die Dateien auf, die nun im Anwendungsverzeichnis vorhanden sind. Im Verzeichnis »myapp/viewer-webapp/src/main/webapp/WEB-INF« befinden sich die Konfigurationsdateien der Anwendung. Die Datei »isis.properties« enthält die drei Domänendienste »ToDoItemsJdo« , »AuditServiceDemo« und »ToDoItemsFixtureService« , von denen nur der erste in einer produktiven Umgebung aktiviert sein sollte. In die Datei »persistor_datanucleus.properties« kann der Entwickler eine andere Datenbankverbindungs-URL eintragen. In der Datei »shiro.ini« finden sich die Sicherheitseinstellungen. Die Passwörter der aktuell registrierten Benutzer stehen in »authentication_file.passwords« .

Tabelle 1

Dateien und Klassen

Pfad

Inhalt

myapp/dom

Das Domänenmodell mit den Klassen »ToDoItem« und »ToDoItems« und deren Audit-Klassen »AuditServiceDemo« und »AuditEntry«

myapp/fixture

Testdaten mit den Klassen »ToDoItemsFixture« und »ToDoItemsFixtureService«

myapp/objstore-jdo

Umsetzung des »ToDoItems« -Repository mit JDO

myapp/viewer-webapp

Wicket-Viewer und »RestfulObjects« -Viewer

Optional sind folgende Verzeichnisse

myapp/tests-junit

Unit-Tests

myapp/tests-bdd

Szenarios für Behavior-Driven Development

Variation

Eine interessante Abwandlung des Standardbeispiels wäre es, statt der To-do-Listen- eine Bücherverwaltung zu programmieren. Dazu löscht man in der Maven-Datei »myapp/pom.xml« die nicht benötigten Module »fixture« , »tests-junit« und »tests-bdd« , sodass nur noch das Domänenmodell, die Persistenzschicht und die Webschicht übrig bleiben (Listing 2). Danach erstellt der Entwickler im Verzeichnis »myapp/dom« das Domänenmodell mit den Klassen »Book« und »Books« . Damit die Services der Domänenobjekte verfügbar sind, fügt er die Zeile

Listing 2

myapp/pom.xml

01 <modules>
02   <module>dom</module>
03   <module>objstore-default</module>
04   <module>webapp</module>
05 </modules>
isis.services = dom.todo.Books

in der Datei »myapp-viewer-webapp/src/main/webapp/WEB-INF/isis.properties« hinzu. Um Bücher speichern zu können, erbt die Klasse »Books« von der allgemeinen Klasse »AbstractFactoryAndRepository« (Listing 3).

Listing 3

Klasse Books

01 @Named("Books")
02 public class Books extends AbstractFactoryAndRepository {
03         @Override
04         public String getId() {
05                 return "Books";
06         }
07         // {{ NewBook (action)
08         @MemberOrder(sequence = "1")
09         public Book newBook(@Named("Name") String name,
10                         @Named("Author") String author) {
11                 Book book = newTransientInstance(Book.class);
12                 book.setName(name);
13                 book.setAuthor(author);
14                 persist(book);
15                 return book;
16         }
17 }

Diese Klasse enthält nur die Methode »newBook()« zum Anlegen neuer Büchereinträge mit den Attributen »Name« und »Author« . Die Entitätsklasse »Book« erbt wiederum von der allgemeinen Klasse »AbstractDomainObject« und besitzt vier Attribute. Dabei sind nur die beiden Attribute »Name« und »Author« an der Oberfläche zu sehen und editierbar. Das allgemeine Attribut »Title« , das aus dem Buchnamen gefüllt wird, dient nur der Anzeige in der Isis-Oberfläche (Listing 4). Das »description« -Attribut bleibt zunächst unsichtbar.

Listing 4

Klasse Book

01 @javax.jdo.annotations.PersistenceCapable(identityType = IdentityType.DATASTORE)
02 public class Book extends AbstractDomainObject {
03         private String name;
04         private String author;
05         public String title() {
06                 final TitleBuffer buf = new TitleBuffer();
07                 buf.append(getName());
08                 return buf.toString();
09         }
10         private String description;
11         @Hidden
12         public String getDescription() {
13                 return description;
14         }
15         @MemberOrder(sequence = "1")
16         public String getName() {
17                 return name;
18         }
19         public void setName(String name) {
20                 this.name = name;
21         }
22         @MemberOrder(sequence = "2")
23         public String getAuthor() {
24                 return author;
25         }
26         public void setAuthor(String author) {
27                 this.author = author;
28         }

Nach dem Anstoßen des Übersetzungsvorgangs mit »mvn install« huschen die Erfolgsmeldungen über das Terminal, dass Isis die Bestandteile der Anwendung samt Weboberfläche baut. Beim Starten der Webanwendung mit »mvn antrun:run« erscheinen zunächst Debugmeldungen von Datanucleus, die zeigen, dass das Framework automatisch die Tabelle zum Speichern der Bücher anlegt. Die Entität erscheint schließlich mit dem Titel »Linux Magazin« in der Weboberfläche (Abbildungen 3a und 3b).

Abbildung 3a: Die Isis-Anwendung zur Buchverwaltung mit Mobil-Oberfläche.

Abbildung 3a: Die Isis-Anwendung zur Buchverwaltung mit Mobil-Oberfläche.

Abbildung 3b: Ein neues Buch ist angelegt – um das Speichern kümmern sich Isis und JDO.

Abbildung 3b: Ein neues Buch ist angelegt – um das Speichern kümmern sich Isis und JDO.

Ausblick und Fazit

Den Ägyptern galt Isis als Gottesmutter, die den zerstückelten Körper ihres Gatten wieder zusammenzusetzen und auferstehen ließ. So möchte auch Apache Isis die fachlich zusammengehörigen Teile über den gesamten Lebenszyklus begleiten und nicht über mehrere Schichten verstreuen. Da Isis unter dem Apache-Dach zu Hause ist, profitiert es auch von den vielen dort vorhandenen Java-Frameworks.

Apache Isis selbst beruht auf seit Langem bekannten Mustern und Frameworks, sodass die aktuellen Versionen schon einen ausgereiften Eindruck hinterlassen. Da auch die Google App Engine die von Apache Isis verwendeten Bibliotheken unterstützt, ist es ohne Änderungen möglich, eine Isis-Anwendung entweder mit dem mitgelieferten Jetty-Webserver, dem Java-Applikationsserver der eigenen Wahl oder auf einer PaaS in der Cloud laufen zu lassen.

Es ist zu hoffen, dass sich mit Isis die REST-ful-Objects-Spezifikation als unabhängiger Standard weiter verbreitet, damit es einfacher wird, Hypermedia-orientierte Webanwendungen zu entwickeln und mit verschiedenen Webframeworks zu kombinieren. (mhu)

Infos

  1. Domain-Driven Design (DDD): http://de.wikipedia.org/wiki/Domain-Driven_Design
  2. Dan Haywood, “Domain-Driven Design using Naked Objects”: Pragmatic Programmers, 2009
  3. REST-ful Objects Specification: http://restfulobjects.org
  4. Typische Anwendungsfälle von Apache Isis: http://isis.apache.org/learning-more/common-use-cases.html
  5. Richard Pawson, Department of Computer Science, Trinity College, University of Dublin, “Naked Objects”: http://www.nakedobjects.org/downloads/Pawson%20thesis.pdf
  6. Naked-Objects-Pattern: http://de.wikipedia.org/wiki/Naked_Objects
  7. Online-Demo zu Apache Isis: http://mmyco.co.uk:8180/isis-onlinedemo/doc/index.html
  8. Einstieg in Apache Isis: http://isis.apache.org/getting-started/quickstart-archetype.html

Der Autor

Frank Pientka ist Senior Software Architect bei der Materna GmbH in Dortmund. Er ist zertifizierter SCJP und Gründungsmitglied des iSAQB. Als Autor des Buches zu Apache Geronimo beschäftigt er sich viel mit in Java umgesetzter Open-Source-Software.

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 4 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Inline Feedbacks
Alle Kommentare anzeigen
Nach oben