Markus studiert!
What The Foto: API-Dokumentation
Ein nicht unerheblicher Teil meiner Arbeit am Projekt ist in die Erstellung einer übersichtlichen API-Dokumentation geflossen.
Wichtig war mir dabei, dass beide Teams einen guten Überblick darüber bekommen, welche Schnittstellen es gibt, und welche bereits implementiert sind — gerade letztere Information war für das Frontend-Team wichtig, damit sie wissen, welche Funktionen serverseitig schon unterstützt werden und mit welcher Funktion man dann dementsprechend im Frontend weiter machen kann.
XML als Basis
Ich hatte bereits aus früheren Projekten mit der Dokumentation von APIs zu tun, und habe mich daher als Basis für eine XML-Datei entschieden.
Zum Einen kann diese manuell leicht gepflegt werden, und mit einer passenden XSD bekommen Entwickler in einer IDE wie Eclipse auch direkt Fehlermeldungen angezeigt, wenn Sie Angaben eintragen, die nicht korrekt sind.
Zum Anderen — und dazu ist es leider nicht gekommen — kann die XML-Datei auch mittels Reflection aus bestehendem Quellcode generiert werden. Im Idealfall hat man im Verlaufe eines Projektes ein sauber dokumentiertes API-Package, dessen JavaDoc in das in der XML verwendete Format transformiert werden kann. Zeitlich sind wir leider nicht soweit gekommen, und so haben die Teams die XML-Datei manuell gepflegt.
Aufbau der XML-Datei
Ziel war es, die Schnittstellen-Kommunikation vollständig zu beschreiben, somit werden im ersten Abschnitt der XML-Datei Datentypen definiert.
Zuerst werden einfache Datentypen definiert.
<simpletype name="String">
<description>Repräsentiert ein String</description>
<example>Lorem ipsum</example>
</simpletype>
<simpletype name="DateTime">
<description>Repräsentiert ein Datum mit Uhrzeit. Das Format ist YYYY-MM-DDTHH:MM:SS+ZZZZ</description>
<example>2011-03-28T17:58:23+0001</example>
</simpletype>
Gefolgt von Enums, die in unserem Fall aus jedem der definierten einfachen Datentypen bestehen dürfen.
<enum name="Sex">
<description>Repräsentiert das Geschlecht einer Person</description>
<example>M</example>
<items>
<item value="M">
<description>männlich</description>
</item>
<item value="F">
<description>weiblich</description>
</item>
</items>
</enum>
Anschließend folgen die komplexen Datentypen, die in der jeweiligen Implementierung ValueObjects oder Models entsprechen.
<complextype name="Lightbox" type="Object">
<description>Repräsentiert eine Lightbox</description></p>
<property name="id" type="Integer" description="ID der Lightbox">
<example>28388</example>
</property>
<property name="name" type="String" description="Name der Lightbox">
<example>Projekt2011</example>
</property>
<property name="description" type="String" description="Beschreibung der Lightbox">
<example>Das ist die Beschreibung der Lightbox.</example>
</property>
<property name="state" type="LightboxState" description="Aktueller Zustand der Lightbox"/>
<property name="created" type="DateTime" description="Das Erstellungsdatum"/>
<property name="modified" type="DateTime" description="Das Datum der letzten Änderung"/>
</complextype>
Wie man sehen kann, habe ich sehr viel Wert auf eine ausführliche Dokumentation der Elemente wert gelegt. Es gibt zu jedem Typ mindestens eine Beschreibung und dort wo es nötig ist auch ein Beispiel für den Inhalt.</p>
Aus diesen Angaben lässt sich dann eine schöne Übersicht mit allen in der Kommunikation verwendeten Datentypen erzeugen.
Zu guter letzt werden die Schnittstellen-Methoden definiert. Diese sind zuerst thematisch gruppiert, in unserem Fall nach den Bezeichnungen der Entitäten aus dem Domänenmodell, z.B. Agency, Photo, Lightbox, User usw.
Innerhalb dieser Gruppe werden dann die dort verfügbaren Methoden definiert. Es werden alle Parameter einer Anfrage beschrieben, wie bei den Datentypen ebenfalls mit ausführlicher Beschreibung und bei Bedarf einen Beispiel, sowie die Art der Antwort.
Da wir mit ActiveMQ ein asynchrones Messaging verwenden und es auch Situationen gibt, in denen Ereignisse eintreten, ohne, dass der Client dazu eine Anfrage gestellt hat, werden auch bei manchen Methoden die dazugehörigen Notifications beschrieben.
<group name="Lightbox">
<description>Enthält Methoden die für Lightboxen benötigt werden.</description>
<action name="enter" inServer="true" inClient="true" messageType="LB_ENTER">
<description>Sobald ein Nutzer eine Lightbox öffnet, tritt er ihr bei.</description>
<request></p>
<property name="session" type="String" description="Die Session-ID des Benutzers">
<example>yvwH8WrBWqz3mabw2TDDTYDUSwDC54HC</example>
</property>
<property name="lightboxID" type="Integer" description="Die ID der Lightbox">
<example>34532</example>
</property>
</request>
<response></p>
<property name="result" type="SuccessMessage" description="Liefert Aussage, ob das Eintreten erfolgreich war."/>
</response>
<notification></p>
<property name="userID" type="Integer" description="userID des Nutzers, der die Lightbox betreten hat">
<example>234544</example>
</property>
<property name="lightboxID" type="Integer" description="Die ID der Lightbox">
<example>34532</example>
</property>
</notification>
</action>
</group>
Daraus lässt sich dann im Wiki eine übersichtliche Darstellung der Methode erzeugen. Durch die vorher definierten Datentypen und die korrekte Einhaltung der Reihenfolge in der XML-Datei, kann der Datentyp eines Parameters direkt mit seiner Definition verlinkt werden.
Zusätzlich können noch mit Hilfe der Ticket-Query-Funktionen von Trac dazugehörige Tickets angezeigt werden.
Die schwarze und weiße Fahne markiert übrigens, dass die Methode von Server und Client fertig implementiert ist. Diese Information ist dann auch in der Seitenleiste der Wiki-Seite (die man hier in voller Größe bewundern kann) einsehbar und bietet so einen schnellen Überblick über den Stand der Implementierung.
Python-Script zum Anlegen der Wiki-Seite
Die Wiki-Seite selber wird mit Hilfe eines Cronjobs über die XMLRPC-API von Trac regelmäßig erzeugt.
Dazu liest dieses Python-Script die XML-Datei aus und erzeugt daraus die Wiki-Seite.
Fazit
Die API-Dokumentation wurde vom gesamten Team sehr stark genutzt auch als sehr positiv empfunden. Leider haben wir in der Design-Phase des Projektes versäumt, explizit den Aufbau der Schnittstellen-Klassen zu definieren, wäre diese früher geschehen, hätte man mit Hilfe der XML-Datei einen automatisierten Satz Unit-Tests schreiben können, der so überprüfen kann, ob die dokumentierte Version der Schnittstelle auch mit den tatsächlichen Gegebenheiten übereinstimmt. Dies hätte auch verhindert, dass im Server eine Schnittstelle still geändert wird und der jeweilige Entwickler keine Möglichkeit hat, seine Änderung auf Auswirkungen bezüglich der Schnittstelle zu prüfen — allerdings hätte dann auch mehr Arbeitsleistung in das reine Testen der Schnittstelle fließen müssen — und das auf beiden Seiten.
< 19. July 2011, 15:36 Uhr