API Design: Die UX der Developer

18.08.2022

Laut einer Studie von Google braucht ein User im Web ca. 50 Millisekunden um zu entscheiden ob er die Website, die er gerade aufruft, gut oder schlecht findet [1].

Im Bruchteil einer Sekunde wird also entschieden, ob er auf der Seite bleiben will oder sie direkt wieder verlässt. Um die Usability und damit auch die User Experience von Softwareanwendungen zu verbessern, wird viel Zeit und Geld in die Verhaltensanalyse der User, das Design und in Tests gesteckt. Dies nennt man auch allgemein User Centered Design (UCD). Man möchte den Usern die beste Experience bieten, um sie an den eigenen Service zu binden.

Die Developer Experience – und der Frust bei schlechtem API Design

Entwicklerinnen und Entwickler müssen sich zwar nicht innerhalb von 50 Millisekunden entscheiden, ob sie eine API gut oder schlecht finden. Aber man merkt dennoch recht schnell, ob sie mit der Qualität einer API zufrieden sind. Ihnen bleibt häufig aber auch keine andere Wahl, als die API zu verwenden. Die Gründe dafür können vielfältig sein: Mal hat der Kunde einen Vertragspartner, dessen System eingebunden werden muss, mal ist es ein anderer Microservice der in das Gesamtsystem integriert werden muss. Wenn man als Developer aber ohnehin auf bestehende APIs zurückgreifen muss, warum sollte man sich dann um so etwas wie eine Developer Experience (DX)[2] bemühen?

Die Antwort ist so simpel wie einleuchtend: Geld. Es kostet viel Geld (und Nerven), schlecht designte APIs zu verwenden. Ich denke jede Entwicklerin und jeder Entwickler hatten in ihrer Karriere schon das Vergnügen, eine schlechte API anzubinden. Merkmale einer unzureichenden API können sein:

  • Sie ist schlecht dokumentiert und irreführend
  • die Endpunkte sind unschlüssig designed
  • die HTTP Methoden sind inkonsistent und entgegen der Definition oder Rückgabewerte
  • Fehlercodes sind unvollständig[3].

Es kostet sehr viel Zeit, diese „Knoten“ zu entwirren. Durch die irreführende Dokumentation können Bugs entstehen, die lange Analysezeiten brauchen um gefixt zu werden. Unvollständige Fehlercodes und Rückgabewerte können zu umständlichen Workarounds führen. Die vermeintliche Sicherheit eines GET Requests kann Daten manipulieren. Die Liste der Ursachen für Fehler in der Anbindung einer API sind unendlich lang.

Abgesehen von den Kosten wirft eine schlechte API auch kein gutes Bild auf den dahinterliegenden Service. Denken wir wieder an den Vergleich zu der UI. Ein Service mit einer schlechten UI und einem unschlüssigen UX wird nur ungern genutzt.

Deshalb sollte das Ziel immer sein, von Anfang an eine gute API zu designen. Wie so vieles in der Software Entwicklung ist auch das API-Design bis zu einem gewissen Grad Geschmackssache. Daher ist es sehr wichtig im Unternehmen oder dem Projekt eine API-Guideline zu definieren und sich auf diese zu einigen. Wir bei doubleSlash legen sehr großen Wert auf die Qualität und haben unsere eigenen API-Design-Guidelines definiert. In jedem Projekt, das wir betreuen, wenden wir unsere Standards an um damit eine gewinnbringende API zu designen.

API Dokumentation: Vertrauen ist Gut – Kontrolle ist besser

Viele Projekte haben Sonar in der Entwicklungsumgebung zur Kontrolle der Code Qualität eingebunden. Im besten Fall läuft noch ein zentraler SonarQube Server, der die Code Qualität anhand vieler Metriken messbar anzeigt. Das gleiche ist für API Dokumentationen möglich. Dafür hat die Open Source Community einige Tools zur statischen Codeanalyse (Linter) zur Verfügung gestellt. Dabei unterscheidet man zwischen zwei unterschiedlichen Ansätzen – dem zentralisierten und dezentralisierten Ansatz. Zalando hat mit Zally[4] einen zentralisierten Ansatz. Hier wird ein zentraler Server genutzt, gegen den das gesamte Unternehmen ihre API Dokumentation validiert. Die Verantwortlichkeit liegt also beim Team, das diesen Server betreibt. Alle Teams müssen den Guidelines dieses Servers entsprechen. Stoplight hat hingegen mit Spectral[5] einen dezentralen Ansatz. Sie bieten ein CLI-Tool, das mithilfe einer Konfigurationsdatei die API Dokumentation validiert.

Beide Ansätze lassen sich sehr einfach in eine Build-Pipeline integrieren. Zally und auch Spectral verfügen über ein CLI-Tool, dass sich wunderbar als Build-Step in eine bestehende Pipeline integrieren lässt. Für Spectral sieht die Konfiguration für GitLab so aus:

stages:
 - test

spectralLint:
 stage: test
 image: node:17.1.0-slim
 script:
   - "npx @stoplight/spectral-cli lint path/to/api/*.yml"

Für Zally muss man sich das Tool von der Release Seite herunterladen: https://github.com/zalando/zally/releases und in das Projekt legen. Danach sieht die Konfiguration etwa so aus:

stages:
  - test

zallyLint:
  stage: test
  script: 
    - "path/to/zally --linter-service https://url.to.zallyserver --format pretty lint path/to/api/*.yaml"

Zally hat auch ein inoffizielles Maven-Plugin, das dem Sinn des zentralisierten API lintens bricht. Die Konfiguration dafür sieht folgendermaßen aus:

stages:
 - test

zallyLint:
 stage: test
 image: maven:3-jdk-11
 script: "mvn verify"

und die pom so:

	com.ethlo.zally
	zally-maven-plugin
	${zally.version}
	
		
		MUST
		
		path/to/api
		
		
		target/api_validation_result.yaml
	
	
		
			
				report
				validate
			
		
	
	
		
			
			org.zalando
			zally-ruleset-zalando
			2.1.0
		
	

Gut designte API – und jetzt?

Nachdem nun die API einheitlich designed wurde und den Guidelines entspricht, könnte man meinen, dass die Arbeit damit getan ist. Doch was passiert im Laufe der Wartung und Weiterentwicklung? Während der Entwicklung, kann es durchaus sein, dass durch die Manipulation von Klassen die API verändert wird.
Es könnte ausversehen eine Variable umbenannt werden, ohne das Bewusstsein dafür, dass dadurch die API verändert wird. Es können außerdem Änderungswünsche reinkommen, die zwar im Code implementiert wurden aber nicht in der API Dokumentation. Wie mit jeder Dokumentation steigt im Laufe der Zeit die Wahrscheinlichkeit, dass sie nicht mehr mit dem Code übereinstimmt.

Daher macht es Sinn, auch den Code mit der Dokumentation zu validieren.

Leider existieren keine akzeptablen Java Libraries, mit der man einen guten Unit Test zum Vergleichen schreiben könnte. Daher muss man hier auf CLI-Tools zurückgreifen. Mit der OpenAPI Diff CLI von Atlassian[7] könnte man so einen „nightly validation job“ konfigurieren. Um den validation job produktiv nutzen zu können, braucht der Service einen Endpunkt, der die openAPI Spezifikation aus dem Code generiert und nach außen freigibt. In diesem Beispiel nehmen wir uns dafür springdoc[8] zur Hilfe.

Die Dependency muss nur in die Maven Dependencies hinzugefügt werden:

 
	org.springdoc
	springdoc-openapi-ui
	1.2.32

Nun kann man einen build job aufsetzen, der bei der Ausführung die generierte openAPI Dokumentation mit der Spezifikation vergleicht:

compare:
  stage: test
  image: node:17.1.0-slim
  script: npx openapi-diff http://url.to.service/v3/api-docs localOpenApiDoc.yml

Qualitatives API Design: Die doubleSlash REST-API-Guidelines

Wir von doubleSlash haben uns für Spectral als API-Linter entschieden. Dafür haben wir unsere API-Guidelines in einem Regelset abgebildet. Wir haben uns entschieden, dass wir dieses Regelset öffentlich machen wollen, damit andere Teams und Unternehmen auch davon profitieren können. Dieses Regelset haben wir als NPM-Package im NPM-Registry veröffentlicht. Außerdem haben wir die Regelsets auf GitHub bereitgestellt. Damit man auf dieses Regelset zugreifen kann, muss das Regelset zuerst über eine package.json Datei importiert werden:

package.json

{
   "dependencies": {
   "@doubleslashde/rest-complete-set": "1.1.0",
   "@stoplight/spectral-cli": "^6.1.1"
   },
   "scripts": {
   "lint": "spectral lint path/to/api/*.yml"
   }
}

Zudem ist es erforderlich das Regelset in der .spectral-Datei zu verwenden:

.spectral

extends:    
   - '@doubleslashde/rest-complete-set'

Ist das erledigt, muss die CI/CD Pipeline nur noch die dependencies installieren und das Script ausführen:

npm install
npm run lint
Fazit: Mit guten API Design zu einer guten Developer Experience

Wie wir nun gesehen haben, ist es sehr wichtig eine gute API zu designen, um eine gute Developer Experience zu schaffen. Um das zu gewährleisten, reicht es aber nicht aus, „nur“ eine Guideline zu erstellen und sich darauf zu verlassen, dass sie genauso umgesetzt werden kann. Eine statische Code Analyse ist hier unabdingbar. Aus demselben Grund wie man SonarQube einsetzt, um die Qualität des Codes zu gewährleisten, sollte man auch einen Linter für die APIs einsetzen um die Qualität der Endpunkte zu gewährleisten. Mit Spectral bekommt man ein sehr gutes CLI Tool an die Hand, mit der man seine Dokumentation gegen die Guidelines prüfen kann.

Manchmal ist einem als Entwicklerin oder Entwickler nicht klar, welchen Schaden man anrichten kann, wenn man zu wenig Zeit investiert, um eine gute API zu designen. Vielleicht ist auch gerade kein Budget vorhanden oder der Fokus liegt gerade auf anderen Features. Mit einem Linter kann man gegen solche Dynamiken ankämpfen und stets eine gute API Dokumentation gewährleisten. Ich hoffe, dass ihr den Artikel bei der nächsten API Design Entscheidung beherzigt und vielleicht sogar in Betracht zieht eure APIs mit einem Linter zu prüfen. Spectral liefert out of the Box schon ein ausführliches Ruleset an, dass man als Basis für seine APIs verwenden kann.

Ich wünsche viel Spaß beim Ausprobieren. Teilt uns gerne mit, ob sich euer API-Design durch einen Linter verbessert hat.

 

Mehr über User Experience erfahren

Quellen:

[1] https://research.google/pubs/pub38315/
[2] https://hackernoon.com/the-best-practices-for-a-great-developer-experience-dx-9036834382b0
[3] https://desmart.com/blog/why-do-we-create-bad-apis
[4] https://github.com/zalando/zally
[5] https://github.com/stoplightio/spectral
[6] https://blog.logrocket.com/common-api-mistakes-and-how-to-avoid-them-804fbcb9cc4b/
[7] https://bitbucket.org/atlassian/openapi-diff/src/master/
[8] https://springdoc.org/

Zurück zur Übersicht

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

*Pflichtfelder

*