JAX 08: API-Design - Entwurf stabiler und beständiger Schnittstellen

von Thomas Bahn,
assono GmbH, Standort Kiel,



Arno Haase, Sven Efftinge:
API-Design ? Entwurf stabiler und beständiger Schnittstellen

API - Application Programming Interface
SPI - Service Provider Interface -

  • Art von API zur Konfiguration,
  • siehe Strategy-Pattern, Listener, Callback-Funktionen
  • in Java häufig Interface
  • Clients müssen SPI implementieren

Bestandteile eines Java-APIs

  • statische Elemente (klar)
  • aber auch dynamische Elemente: Aufrufreihenfolgen, wann wird welche Exception geworfen, Anforderungen an implementierenden Client-Code, nicthfunktionale Eigenschaften

API-Bestandteile sprachabhängig

von schwache Typisierung (Ruby) bis
Design by Contract (Eiffel)


Weitere Bestandteile

  • Dateiendungen, -formate und inhalte
  • Umgebungsvariablen

Veröffentlichte Schnittstelle

  • Schnittstellen sind explizit: klare Dokumentation, öffentliche Member (gehören nicht unbedingt zur Schnittstelle, können aber technisch notwendig sein)
  • Schnittstellen bleiben stabil, aber Implementierung darf geändert werden
  • Trennung schafft Herausforderungen: keine Kontrolle über die Benutzer der Schnittstelle
  • Je weiter die Trennung, desto schwieriger sind Änderungen

Was ist ein gutes API?

  • klarer Scope
  • schlank
  • einfach zu benutzen
  • lesbar
  • intuitiv und überraschungsfrei
  • komplett und redundanzfrei

Best Practices (Vorgehen)


Use Case-zentriert

Design aus Sicht des Clients

  • Validierung der Abstraktionen
  • welche Probleme soll die Bibliothek für Clients lösen
  • Test-Driven Development (TDD)
  • "Eat your own dog food"

Gegengewicht zu Abstraktionen aus Sicht
der Bibliothek

  • beide Richtungen müssen "stimmig" sein

Klare Abstraktionen

gute Abstraktionen sind

  • intuitiv
  • einfach, aber nicht zu einfach
  • passend zur Domäne
  • redundanzfrei und dadurch wiederspruchsfrei

Domänenanalyse

  • Use Cases/Szenarien durchspielen
  • klarer Scope

Iterative Entwickung

Schnittstelle vor der Veröffentlichung
reifen lassen

  • erst zwei, drei Systeme bauen, die die API nutzen
  • "Three strikes and you refactor"

Explizite Releases

Anders als "normaler" Code
hat ein API zwingend klare Releases

  • eingefroren
  • Versionierung

Vorab-Tests
sind möglich


Mut zur Lücke

Es gibt typischerweise Druck, schnell
zu veröffentlichen

  • Termindruck beim API-Entwurf und durch Kunden, die die Lösung brauchen

Best Practices (Design)


Explizites API

Trennung von API und Implementierung

  • Klare Liste der "öffentlichen" Klassen und Interfaces
  • Klare Beschreibung des "garantierten" Verhaltens, Abgrenzung von Implementierungsdetails
  • erlaubte Verwendungsmuster (Reihenfolge, Threading, etc.)
  • API muss vollständig sein

Einfaches API

Man kann APIs leicht erweitern, aber
schwer wieder Elemente entfernen

Einfach zu lernen

  • möglichst wenige Konzepte
  • möglichst wenige Aufrufe

Einfach
zu pflegen und zu erweitern

  • Redundanzfreiheit

Gute
Defaults

  • Configuration by Exception
  • Programming by Convention

Facade

  • einfache Facade für häufige Use Cases anbieten, um Komplexität optional zu machen

Convenience-Methoden
für häufig verwendete Aktionen

Checked Exceptions sinnvoll?


Einfachheit SPI

Ein Interface kann nicht erweitert werden!

Ein Interface sollte möglichst wenig
Methoden deklarieren

Trennung von API (nicht reduzierbar)
und SPI (nicht erweiterbar)

Anbieten einer abstrakten Defaultimplementierung


Überraschungsfreiheit

Unveränderliche Datentypen

Annahmen im Code explizit machen

  • Sichtbarkeiten, Dokumentation

Gute
Name wählen

Fehlbedienung zur Laufzeit melden

  • Contract-Verletzungen sofort abweisen
  • klare Fehlermeldungen

API-Separierung

Trennung eines großen APIs in überschaubare
Teile mit klarem Fokus

Beispiele

  • Swing (schlecht)
  • SWT --> JFace --> Workbench (gut)

Best Practices (Implementierung)


Interfaces oder Klassen?


kein globaler Zustand

globaler Zustand verschleiert Abhängigkeiten

  • z. B. Konfiguration in einem Singleton, das sich aus einer Datei initialisiert
  • Initialisierung des globalen Zustands ist implizierte Vorbedingung für die Verwendung
  • Infrastruktur-Anforderungen für Client-Tests

Unveränderlichkeit (Immutability)

Pro

  • einfach
  • threadsicher
  • wiederverwendbar

Contra

  • für jeden Wert ein neues Objekt

Methoden statt Feldern

Methoden kapseln Implementierungsdetails

  • z. B. bei einfachen Parameterklassen ohne Interface
  • Wertebereichsprüfung auf Contract-Konformität
  • Namen und Typen der Felder

aber
nicht dogmatisch?


Factories

Factories kapseln Details der Erzeugung

  • konkrete Typen
  • Lifecycle
  • Multiplizität - Reuse bei zustandslosen Services

Große Auswahl an Entwurfsmustern

Service-Repositories als Spezialfall

  • DI im Stil von Spring

Verwendung explizit im Code

Java bietet Sprachmittel, um einen beabsichtigte
Verwendung im Quelltext explizit zu machen

  • final
  • private Konstruktoren

Listener

Listener erlauben die Erweiterung eines
API an wohldefinierten Stellen

  • use case-getriebene Auswahl der Stellen
  • clientspezifische Funktionaltät

Klarer
Contract für Listener

  • u. U. andes als "normale" API-Verwendung
  • evtl. Einschränkung der erlaubten Aufrufe
  • Thread-Modell

API-Evolution: Problemstellung

APIs behindern die Evolutions der Bibliothek

Anforderungen ändern sich


Lebenszyklus von Schnittstellen

viergeteilter Lebenszyklus

  • Draft
  • Published
  • Deprecated
  • Retired

SPI-Evoution

Möglichkeiten

  • neue Interfaces
  • mit Vererbungshierarchie
  • Refactoring mit API-Bruch

Neues Interface für Änderung

  • bei jeder Änderung wird ein Interface hinzugefügt

Auswirkungen

  • Explosion!

Framework-Code

Typ abfragen und casten


Vererbungshierarchie von Interfaces

neue Interfaces erweitern die alten


Refactoring mit API-Bruch

aufräumen!

Veranstaltung Fachbeitrag JavaScript Java Sonstiges

Sie haben Fragen zu diesem Artikel? Kontaktieren Sie uns gerne: blog@assono.de

Sie wollen eine individuelle Lösung? Kontaktieren Sie uns

Weitere interessante Artikel

Sie haben Fragen oder möchten eine Demo anfordern?

Wenn Sie mehr über unsere Angebote erfahren möchten, können Sie uns jederzeit kontaktieren. Gerne erstellen wir eine individuelle Demo für Sie.

Wir verwenden Ihre Daten, um Sie einmalig per E-Mail zu kontaktieren. Wir geben Ihre Daten nicht an Dritte weiter. Siehe: Datenschutzhinweise
assono GmbH

Standort Kiel (Zentrale)
assono GmbH
Lise-Meitner-Straße 1–7
24223 Schwentinental

Standort Hamburg
assono GmbH
Bornkampsweg 58
22761 Hamburg

Telefonnummern:
Zentrale: +49 4307 900 407
Vertrieb: +49 4307 900 402

E-Mail-Adressen:
kontakt@assono.de
bewerbung@assono.de