Techblog

Documentation First

Von David Eibl

9. Februar 2018

„Test First“ kennt jeder. Warum nicht mal „Documentation First“?

Einheitliche Schnittstellen haben heute mehr Bedeutung als noch vor zehn Jahren. Die meisten Softwareprojekte kamen ganz ohne Schnittstellen aus, bei manchen gab es einzelne, sehr spezifische Schnittstellen zu Umsystemen.

Was hat sich geändert? Während in der traditionellen JEE-Welt Frontend und Backend starr verdrahtet waren, werden sie heute unter Einsatz von Frontend-Technologien wie AngularJS durch klar definierte http-Schnittstellen entkoppelt. 

Dazu kommt, dass immer mehr Anwendungen als Microservices gebaut werden. Ein wichtiger Bestandteil sind neben der asynchronen Kommunikation die synchronen Schnittstellen, meist gemäß REST implementiert.

Einzelne Komponenten werden häufig von unterschiedlichen Teams entwickelt. Die Schnittstellen unterstützen dabei, die einzelnen Komponenten zu entkoppeln. Essenziell ist eine gute Dokumentation dieser Schnittstellen. Sehr einfach geht das mit Swagger.

Swagger ist ein Open-Source-API-Framework. Es hilft, APIs zu definieren, anderen zugänglich zu machen und Code zu generieren. Swagger besteht aus folgenden Komponenten:

Swagger Editor

Der Editor lässt sich direkt im Browser verwenden oder ist hier als Download verfügbar. In ihm lassen sich mit YAML- oder JSON-Syntax die Schnittstellen gemäß der OpenAPI-Spezifikation bestimmen. Definiert werden können alle konkreten Endpoints, Einstellungen wie API-Version oder mögliche Formate und wie die Data-Transfer-Objekte aussehen.

Swagger UI

Swagger UI ist eine grafische Web-Oberfläche. Sie ermöglicht es, alle Schnittstellen zu dokumentieren und manuell zu testen. Als Basis dient ein YAML- oder JSON-File. Das kann mit dem Swagger Editor erstellt oder aus der Implementierung generiert worden sein, unterstützt durch Annotations im Quellcode. Wie das aussieht, kann man sich beispielsweise bei Zalando ansehen. 

Swagger Codegen

Mit dem Swagger Codegenerator ist es möglich, aus einer API-Spezifikation gemäß OpenAPI einen Quellcode zu generieren. Generiert werden können alle definierten Data-Transfer-Objekte, REST-Endpoints, aber auch vollständige Anwendungen. Oft kommt die Dokumentation erst nach der Implementierung. Der Codegenerator krempelt diesen Prozess um und folgt einem neuen Ansatz: Zuerst wird die Spezifikation geschrieben, die mit Swagger UI als Dokumentation dient, erst dann folgt die Implementierung. Der Codegenerator ist in den Swagger Editor integriert. So lassen sich Clients und Server-Komponenten einfach per Mausklick aus der Definition generieren. Die Definition wird für diverse Programmiersprachen und Frameworks angeboten.

Schnelles Prototypen

Eine gute Voraussetzung für schnelles Prototypen: Zum einen wird der ganze Projekt Boiler-Code generiert. Zum anderen hat man sofort ein lauffähiges Programm mit allen Schnittstellen (Server) oder der Implementierung für den Zugriff darauf (Client).  

Swagger lässt sich aber auch in Projekten verwenden, die über einen Prototyp hinausgehen. Dazu kann man den Codegenerator in den Build-Prozess integrieren.

Vorteile:

  • Generierte Quellcode-Dateien werden sauber von den selbst geschriebenen getrennt, das Einchecken von generierten Klassen entfällt.
  • Manuelles Schreiben des häufigen Boiler-Code für REST-Endpoint und simple Datenhaltungsklassen entfällt.
  • Man braucht weniger Anpassen von Änderungen an der Schnittstelle.
  • Swagger UI lässt sich einfach einbinden und kann für andere die angebotenen Schnittstellen dokumentieren.
  • Das YAML-File stellt immer die Wahrheit dar, daraus generierte Server und Clients sind sofort kompatibel.

Sinnvoll ist es, die YAML-File in einem teamübergreifenden Versionskontroll-System abzulegen. So wird die dort vereinbarte Wahrheit festgehalten. Über Mechanismen wie Pull-Requests können Änderungen vorgenommen werden.

Nachteile:

  • Es gibt dutzende unterschiedliche Generatoren, die sich sehr unterschiedlich entwickeln.
  • Jeder Generator unterstützt andere Konfigurationen und hat kleine Probleme, die an anderer Stelle schon behoben wurden.
  • Es ist auf REST-Schnittstellen beschränkt.
  • Asynchrone Kanäle wie Message Queues lassen sich nicht gut abbilden.

Und wie arbeitet es sich damit?

Meine Erfahrung: Wir verwenden Swagger seit etwa einem Jahr im Projekt und haben damit insgesamt sehr positive Erfahrungen gemacht. Allerdings merkt man dem Codegenerator an, dass es ein sehr großes Opensource-Projekt ist. Er verbessert sich jedoch kontinuierlich. Dank Opensource können wir auch selbst Lösungen einbringen. Die Community unterstützt dabei aktiv. 

Swagger UI ist eine angenehme Art, seine API anderen zur Verfügung zu stellen. Es lässt sich unkompliziert in eine bestehende Anwendung generieren. Zur Dokumentation von REST-Schnittstellen erweist es sich als sinnvoll.

Ob die Verwendung des Swagger-Codegenerators in großen Projekten sinnvoll ist, stelle ich in Frage.

Für einen kleinen Hackathon oder Prototypen bietet der Swagger-Codegenerator eine tolle Möglichkeit, schnell ein laufendes Programm zu bekommen – und zwingt einen, die Schnittstellen sofort klar zu definieren und damit auch zu dokumentieren.

Kommentare

>Ob die Verwendung des Swagger-Codegenerators in großen Projekten sinnvoll ist, stelle ich in Frage.

Wie geht ihr stattdessen vor?

Hi Rupert,

da der beschriebene Ansatz bei uns gut funktioniert, haben wir diesen beibehalten.
Im Nachhinein betrachtet haben wir aber relativ viel Zeit damit verbracht, die Generierung anzupassen und mussten einige Workarounds implementieren bis es lief. Um ein Beispiel zu nennen: Die generierten Klassen enthalten nicht verwendete Imports, die nicht Teil der Java-Standart-Libraries sind. Da wir die generierten Klassen nicht anfassen wollten, mussten wir deswegen leere Klassen mit passenden Packages anlegen, damit die generierten Klassen keine Compile-Fehler erzeugen. 
Das nächste Mal könnte man diese Workaround zwar sofort wieder einsetzen und würde den zeitlichen Aufwand stark reduzieren, es bleibt aber das Gefühl, dass der Codegenerator noch nicht ganz ausgereift ist. Es kann gut sein, dass das mit kommenden Versionen besser werden wird. 
Für das nächste Projekt würde ich eher den "traditionelleren" Weg wählen, mit Swagger zu arbeiten, indem wir Transportobjekte und Restendpoints selber schreiben und mit Swagger Annotations versehen. Daraus lässt sich eine Swagger-File generieren, dass die Wahrheit der Implementierung darstellt. Dieses könnte man dann weitergeben oder automatisiert gegen eine existierende Definition abgleichen. 

Hi David,

 

schöner Artikel! Die Aussage "Wahrheit der Implementierung" würde ich aber mit Vorsicht genießen. Bestimmte Aspekte lassen sich nur bedingt (401/403 von zentralen Sec-Komponenten) oder gar nicht (503 der umgebenden Infrastruktur) automatisch generieren.  Alles in allem aber ein spannendes Thema. Insbesondere da mit OpenAPI 3.0 jetzt auch endlich eine bessere Unterstützung für Content-Type Negotiation kommt. Beste Grüße Florian

Würde ich auch gerne mal einsetzten

vielleicht im nächsten Projekt?

Hallo David,

cooler Artikel, vielen Dank dafür! Als TDD Fanboy würde ich einwenden wollen, dass Tests doch (automatisch überprüfbare) Dokumentation sind und damit Test first auch Documentation first ;) Auch wenn ich Codegenerierung im Allgemeinen eher skeptisch gegenüber stehe (Du schreibst ja selbst von entsprechenden Erfahrungen) und mich bei generierter Doku immer zuerst frage, ob diese denn nicht redundant sein _muss_ wenn sie ja generiert werden konnte, bekomme ich schon Lust, es mal auszuprobieren.

Neuen Kommentar schreiben

Public Comment form

  • Zulässige HTML-Tags: <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd><p><h1><h2><h3>

Plain text

  • Keine HTML-Tags erlaubt.
  • Internet- und E-Mail-Adressen werden automatisch umgewandelt.
  • HTML - Zeilenumbrüche und Absätze werden automatisch erzeugt.

ME Landing Page Question

Erhalten Sie regelmäßig Praxis-Tipps per E-Mail

Praxis-Tipps per E-Mail erhalten