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








