Ports and Adapters – Eine Software-Architektur für moderne Applikationen

Autor / Redakteur: Benjamin Klüglein / Sebastian Gerstl

Klassische Software-Architektur ähnelt oft einem Schichtensalat. Doch das, was Sie auf eine Party mitbringen würden, eignet sich nicht als Basis für moderne Anwendungen. Die bessere Alternative: Ports and Adapters

Anbieter zum Thema

Klassische Schichtenarchitektur: Idealvorstellung; jede Schicht kennt nur die jeweils darunterliegende. Bei Ports and Adapter wird die Anwendung dagegen Anstatt der üblichen Schichten in die Namen gebenden Ports und Adapter eingeteilt.
Klassische Schichtenarchitektur: Idealvorstellung; jede Schicht kennt nur die jeweils darunterliegende. Bei Ports and Adapter wird die Anwendung dagegen Anstatt der üblichen Schichten in die Namen gebenden Ports und Adapter eingeteilt.
(Bild: Method Park)

Er ist auf jeder Party ein gern gesehener Gast. Optisch macht er so einiges her, wie sich der Mais so an die Mayonnaise schmiegt, wie der Sellerie mit dem Kochschinken eine Symbiose eingeht und die Ananas ihm das gewisse Etwas verleiht. Dank seines meist gläsernen Gefäßes kann ihn jeder bereits von weitem auf dem Buffet bewundern - den Schichtsalat! Am nächsten Morgen jedoch offenbart sich ein anderes Bild. Aus den einst fein säuberlich eingezogenen Schichten ist eine klumpige Masse geworden. Was einmal appetitlich und einladend aussah, erinnert nur noch vage an den Star der gestrigen Salatauswahl.

Jeder, der Anwendungen entwickelt, kennt vielleicht ein ähnliches Problem. Was vor Wochen und Monaten noch eine gute Architektur schien und deutlich als einzelne Schichten abzeichnete, erscheint plötzlich in einem ganz anderen Licht. Es fällt schwer die einzelnen Schichten noch als solche zu erkennen. Zu sehr sind Details aus der Geschäftslogik in die Darstellung eingeflossen, und die Wahl der Datenbank bestimmt über die Funktionalitäten. Die Anwendung lässt sich nur unter Schwierigkeiten in Teilen, geschweige denn in ihrer Ganzheit testen. Man stellt sich die Frage, was ist noch Mais, was ist schon Datenbank? Nun tauchen auch noch die Steakholder auf und wollen weitere Features integriert haben! Nur, wo soll man nun die neue Schicht Erbsen bloß einziehen?

Bildergalerie

Wem diese Probleme bekannt vorkommen, dem sei versichert: Es kann geholfen werden. Denn mit „Ports and Adapters“ hat Alistair Cockburn ein Architekturmuster definiert, das genau diesen Problemen begegnen soll. Der vorliegende Artikel beschreibt den Einsatz dieses Musters in der Praxis und zeigt dessen Vor- und Nachteile auf.

Houston, haben wir ein Problem?

Sind in unserem Salat-Beispiel die Probleme mehrheitlich ästhetischer Natur, so zeigen sich bei Anwendungen nach einem Schichtenmuster handfeste Probleme. Zunächst wollen wir die klassische Schichtenarchitektur betrachten. Sie besteht zumeist aus drei Schichten:

  • Der Datenhaltungsschicht, die für die Speicherung der Anwendungsdaten zuständig ist,
  • der Logikschicht, die das Herzstück der Anwendung darstellt,
  • und zuletzt der Darstellungsschicht, zuständig dafür die Daten anzuzeigen und mit dem Benutzer zu interagieren.

Um die drei Teile der Anwendung nun koordiniert miteinander kommunizieren zu lassen, legt man meist fest, dass eine Schicht nur mit der unter ihr liegenden Schichten kommunizieren darf. In der Praxis werden jedoch häufig Geschäftslogik und Benutzeroberflächen-Code vermischt. Daraus resultieren folgende Hauptproblemfelder:

  • Die Anwendung kann nicht ohne größeren Aufwand automatisiert getestet werden.
  • Es ist knifflig die Anwendung ganz oder in Teilen wiederzuverwenden beziehungsweise zu ersetzen.
  • Die Entwicklung der einzelnen Anwendungskomponenten lässt sich nur schwer unabhängig voneinander vorantreiben.

Hinzu kommt, dass Anwendungen häufig stark an eine Datenbank, eine Darstellungsform (wie HTML) oder einen externen Service gekoppelt sind. Ändert sich das Datenbankschema oder muss die Datenbank gar durch eine andere ersetzt werden, können Entwickler in ihrer Arbeit blockiert werden und so unnötige Kosten entstehen.

Ein Beispiel aus der Praxis: Eine Anwendung des Kunden nutzte einen proprietären SQL-Datenbank-Server für die Datenhaltung. Für bestimmte Anwendungsfälle wurde die Funktionalität als sogenannte „Stored Procedures“, also als in der Datenbank hinterlegte Funktionen, realisiert. Wann immer ein Benutzer gewisse Anwendungsfälle durchführen wollte, rief er von der Darstellungsschicht über die Persistenzschicht eine entsprechende Prozedur auf. Die Anwendung war somit direkt abhängig von der gewählten Persistenzlösung. Details aus der eigentlich untersten Schicht übertrugen sich bis fast hinauf in die oberste.

Zunächst stellte sich dieser Umstand nicht als Problem dar. Doch nach Jahren der Entwicklung änderten sich die Anforderungen an die Software. Die Anwendung sollte nun vom Datenbank-Server unabhängig sein. Bisher musste zu jeder Installation der Software auch der Datenbank-Server auf dem Rechner installiert werden. Das führte dazu, dass die Rechner mit der entsprechenden Leistung - ausreichend für Datenbank und Anwendung - ausgelegt sein mussten. Günstige Laptops waren demnach keine Alternative. Zudem ging es nicht zuletzt darum Lizenzkosten für jede Installation einzusparen.

Durch die Vermischung von Anwendungslogik und Datenhaltung ließ sich die Persistenzschicht nicht ohne Weiteres auszutauschen. Zur Lösung des Problems wurde ein Service entwickelt, der die Interaktion mit der Datenbank übernahm.

Wäre die Anwendung ursprünglich nach dem „Ports and Adapters“ Muster entwickelt worden, hätte man nicht in eine komplett neue zusätzliche Anwendung investieren müssen. Ein einzelner neuer Adapter wäre ausreichend gewesen.

Im folgenden wird das Prinzip der „Ports and Adapters“ genannten Architektur in vier Schritten näher erläutert.

Definieren von Adaptern und Ports

Anstatt der üblichen Schichten wird die Anwendung in die Namen gebenden Ports und Adapter eingeteilt. Adapter sind Komponenten nach dem klassischen Adapter-Pattern der Gang of Four. Das Wort „Port“ wurde gewählt, um an die Ports eines Computers zu erinnern. An einen solchen Port kann ein beliebiges Gerät angeschlossen werden. Dazu muss es lediglich das Protokoll des Anschlusses verstehen. Für jedes Gerät gibt es einen Adapter, der zwischen der API und den Signalen übersetzt, die das Gerät benötigt. Ein passendes Beispiel hierfür sind die USB-Anschlüsse an einem Rechner. Von Abschussrampen die Schaumstoffpfeile verschießen, bis zu Tastaturen und Mäusen kann man dank einheitlicher Schnittstelle alles anschließen und betreiben.

Dieses Bildnis aus Anschlüssen und Adaptern lässt sich leicht auf Teile von Anwendungen übertragen: Die Benutzeroberfläche (GUI - Graphical User Interface) ist ein Beispiel für einen Adapter, der die Kommunikation zwischen Nutzer und Anwendung ermöglicht. Eine Datenbank ist ein Adapter, der die Datenhaltung verwaltet.

Eine Anwendung nach dem „Ports and Adapters“-Muster lässt sich generell wie folgt darstellen: Ein Sechseck wird verwendet, um zu verdeutlichen, dass eine Innen- und Außenasymmetrie besteht und dass verschiedene, in ihrer Funktion ähnliche Ports gibt. Es soll zudem darstellen, dass es eine Anzahl unterschiedlicher Ports vorhanden ist. Dabei geht es nicht um die Zahl Sechs im Speziellen. Vielmehr erhalten Entwickler beim Entwurf Platz, um die verschiedenen Ports und Adapter einzuzeichnen. Der alternative Name des Musters (“Hexagonale Architektur“) leitet sich von dieser Darstellung ab.

Bei Ports werden primäre und sekundäre Ports unterschieden. Primäre Ports sind solche, die die Anwendung anbietet und von außen aufgerufen werden. Die eigentliche Anwendungslogik ist z.B. ein primärer Port.

Sekundäre Ports werden von der Anwendung selbst aufgerufen. Der Port für die Datenhaltung ist ein solcher sekundärer Port.

(ID:44950719)