Was passiert eigentlich, wenn man die Software-Produkt-Dokumentation dem Quelltext einer Software gleichstellt? Sie wird einfacher zu handhaben und erhält einen Stellenwert, der auch Entwickler daran erinnert, sie zu pflegen.

Das Doku-Drama

Eine grundsätzliche Aufgabe in jedem größeren Softwareprojekt ist die Organisation der Erstellung, Pflege und Weiterentwicklung der Software-Produkt-Dokumentation.

Diese wird oftmals nicht parallel zur eigentlichen Software entwickelt, sondern getrennt davon und auch mit zeitlichem Abstand (meist: Verzögerung).

Durch die zeitliche Verschiebung ergibt sich das Problem, dass der Stand der Dokumentation immer mit dem realen Stand der Entwicklung abgeglichen werden muss. Dokumentations-Gärtner:innen müssen den Abschluss der Entwicklung abwarten, um dann das genaue Umsetzungsergebnis zu dokumentieren. Je weiter die Dokumentierenden organisatorisch vom Entwicklungsteam entfernt sind, desto schwieriger gestaltet sich dieser Abgleich.

Die Versionierung der Dokumentation erfordert natürlich den Bezug zur Software-Version, die beschrieben wird. Diese steht aber nicht unbedingt fest, wenn die Dokumentation verfasst wird. Je mehr DevOps mit schnellen automatischen Releases zum Einsatz kommt, um so dynamischer und weniger greifbar wird die Versionsnummer.

Viele Entwicklungsteams tun sich schwer damit, die Dokumentation aktuell zu halten, wenn sie überhaupt erstellt wird. Dafür gibt es viele Gründe, gute und weniger gute. Das beginnt bei der Motivation: Teilweise ist Dokumentation ein zu lieferndes Element, von dem alle wissen, dass es keiner jemals lesen wird oder sie muss nur existieren, um eine bestimmte (interne) Genehmigung zu erhalten. In anderen Fällen ist die Dokumentation wichtig, aber es gibt keine Qualitätskontrolle und kein Dokumentenmanagement - oder ein kompliziertes, manuelles Ablagesystem - wer nichts liefert, muss sich damit nicht auseinandersetzen.

Schließlich gibt es noch Dokumentationspflichten, die unumgänglich sind. In regulierten Umgebungen werden Dokumentationspflichten kontrolliert und eine "Validierer" genannte Rolle überprüft die Korrektheit des Inhaltes. Je nach Anforderungsniveau muss hier sehr viel Zeit investiert werden und jede Form der Arbeitserleichterung in der Dokumentation reduziert den Aufwand für das nächste Release.

Was also tun, um dem Doku-Drama zumindest ein versöhnliches Ende zu bescheren?

Ich nehme in diesem Beitrag die Rolle des Entwicklungs-Teams ein. Wenn also von "wir" die Rede ist, geht es immer um die Mitglieder des Entwicklungsteams, wobei hier, im besten Sinne eines cross-funktionalen Teams, die Business-Analyst:innen, Architekt:innen, DevOps Engineers und Config-Manager:innen mit einbezogen sind. Und natürlich die technischen Autor:innen.

 

Dokumentation als Code

Eine Sache vorweg: Dokumentation ist im Rahmen der Anforderungen zu schreiben. Diese Pflicht kann nicht wegdiskutiert werden, aber im Sinne einer effizienten Arbeitsweise darf die Erstellung von Dokumentation keine überfordernde Aufgabe sein.

Untersucht man die Anforderungen an die Dokumentationserstellung, stellt sich heraus, dass sie in weiten Teilen identisch zu denen sind, die wir an unseren Programmcode stellen: Er soll einfach zu warten sein, er soll verständlich sein und mit dem Produkt versioniert werden. Wir legen Entwurfsprinzipien zugrunde, wie "DRY" (Don’t Repeat Yourself), geringe Kopplung, hohe thematische Kohäsion, um die Pflege zu vereinfachen.

Wenn Anforderungen an Dokumentation und Code in weiten Teilen gleich sind, liegt es nahe auszuprobieren, ob man mit dem Ansatz die Produkt-Dokumentation als Teil des Programmcodes zu sehen, zu einem besseren Ergebnis gelangt.

In den folgenden Abschnitten werden Aspekte des geschilderten Doku-Dramas mit dem Ansatz Dokumentation als Code zu sehen adressiert.

Motivationsfaktoren

Um es vorweg zu nehmen, das Motivationsproblem zu lösen, ist nicht die Aufgabe der Technik. Das Team muss durch die Teamleitung, Scrum-Master und die Projektorganisation auf die Dokumentation eingeschworen werden. Es muss für das Team erkennbar sein, dass ein Nutzen dahinter steht.

Eine einfache Kudo-Karte für eine gelungene Beschreibung kann bereits kleine Wunder wirken. Kommt von der Nachtbereitschaft die Meldung, dass man ein Problem aufgrund des guten Operations-Handbuches lösen konnte, zeigt dies den Autor:innen den Stellenwert des Dokumentierens und bindet das Entwicklungsteam auch emotional ein: Wir wissen, wem diese Zeilen helfen werden. Wir tun es für einen guten Zweck.

Werden Dokumentationspflichten zur Last und dienen weder einem Zweck noch gibt es Interessenten dafür, sollte man als Product-Owner oder Projektverantwortlicher die Erstellung ernsthaft hinterfragen und gegebenenfalls lautstark verweigern.

Den weiteren Situationen versuchen wir mit Automatisierung und Prozess beizukommen.

Dokumentation ist Code

Zunächst ändern wir als Team die Einstellung gegenüber Dokumentation. Wir definieren Dokumentation als Code, der genau wie der Programmcode Teil der Iteration ist. Dies ist aber nicht nur ein Lippenbekenntnis, sondern es werden Fakten geschaffen.

  • Die Dokumentation ist Teil der Definition of Done.
  • Die Erstellung eines neuen Dokumentations-Artefaktes wird identisch behandelt zur Erstellung eines neuen Microservices. Idealerweise liegt die Dokumentation zusammen mit dem dazugehörigen Software-Artefakt in einem Repository.
  • Die Dokumentation wird versioniert und in einer Pipeline oder zusammen mit dem Software-Artefakt ausgeliefert.
  • Die Dokumentation ist eine Abhängigkeit zur Software und wird als solche gepflegt und getrackt.
  • Die versionierte Dokumentation ist wie das versionierte Software-Artefakt im Artefakt-Repository abrufbar.
  • Im Refinement für ein Software-Feature werden als Akzeptanzkriterium die anzupassenden Dokumentations-Artefakte aufgelistet.
  • Der E2E Test unterstützt die Validierung der Software. Zum Beispiel, um die Anforderungen des Qualitäts-Managements zu prüfen (Dokumentenhistorie angepasst, aktuelle Software-Versionen in der Dokumentation hinterlegt, Dateiformate eingehalten, elektronische Unterschriften vorhanden, etc.)

Der dahinterstehende Gedanke ist, dass wir in der Lage sind, die implementierten Funktionen zusammen mit dem von uns entwickelten Code zu dokumentieren. Wir betrachten die Dokumentation als Ergebnis-Artefakt unserer Tätigkeit als Software-Entwicklungs-Team, so, wie wir es mit Docker-Containern oder JAR-Files tun.

Dokumentation als Code schreiben

Wenn man Dokumentation wie Code behandeln möchte, muss man dies in einem Format tun, das sich den automatisierten Werkzeugen der Code-Entwicklung unterwirft. Das wird dem Office-Afficinado schmerzhaft bewusst, wenn die gewohnte Software nur Binärformate liefern kann und daher nicht dazu geeignet ist, einen Dokumentations-Review durchzuführen. Dieser Schritt verlangt insbesondere technischen Autor:innen einiges ab. Entwickler:innen können das mit dem Umstieg auf eine neue Entwicklungsumgebung vergleichen, in der nichts mehr so funktioniert, wie es vorher war und zusätzlich noch dieses seltsame "git" erlernt werden muss. Aber es lohnt sich.

Es gibt diverse Textformate, die sich zur Dokumentation eignen, zu den altbekannten zählt sicherlich DocBook, ein XML Format. Ich kann AsciiDoc und die Toolsuite AsciiDoctor empfehlen (https://asciidoctor.org), da im Gegensatz zu DocBook auch der "Quelltext" sehr gut lesbar bleibt - auch ohne jede Werkzeug-Unterstützung. Dem ebenfalls weit verbreiteten MarkDown stehe ich persönlich skeptisch gegenüber, weil es zu viele Varianten gibt, mit deutlich unterschiedlichem Funktionsumfang. Alle genannten Werkzeuge haben eine gute Tool-Unterstützung, um das Schreiben der Dateien zu vereinfachen.

Vergleich

Tool Review as diff IDE Support Lesbar Graphiken Diagramme im Code Formate Sonstiges
AsciiDoc asciidoctor.org Ja Ja Ja Ja Ja PDF, DOCX, HTML et. al. Aktive Entwicklung, gute Community, sehr gute Dokumentation.
Markdown markdownguide.org Ja Ja Ja Ja Ja PDF, DOCX, HTML et. al. Aktive Entwicklung, gute Community, sehr gute Dokumentation. Propriertäre Erweiterungen
DocBook OASIS Standard Schlecht (XML) Ja Ja Schlecht Ja PDF, Word, HTML et. al. Scheinbar keine aktive Weiterentwicklung.

Produktdokumentation als Artefakt des Software-Systems

Um eine automatische Auslieferung der Dokumentation mit dem Produkt zu gewährleisten, ohne manuelle Prozesse einzuschalten, muss sie Teil des Produktes werden. In der automatischen Dokumenten-Generierung wird die Produktdokumentation mit einem Software-Release in einem Repository verknüpft. Die Dokumentation wird zusammen mit der Software erstellt und versioniert, nicht getrennt.

Da Dokumentation damit zum Bestandteil der Software wird, ist es nur folgerichtig, dass eine Änderung der Dokumentation einen neuen Build auslöst, der schließlich in einem neuen Release-Artefakt mit einer neuen Version endet.

Dies ist erst einmal nicht selbstverständlich und muss ein akzeptiertes Verhalten sein: Es gibt eine neue Version, auch wenn wir “nur” Dokumente und keine Software geändert haben. Man kann argumentieren, dass dies nicht beabsichtigt ist, aber mit diesem Ansatz stellen wir sicher, dass Software und Dokumentation eng miteinander verknüpft sind und sich nicht auf unterschiedlichen Wegen weiterentwickeln. Es wird immer klar sein, welche Version der Dokumentation das Verhalten von welcher Version der Software beschreibt. Es ist dadurch auch sehr einfach, die Software und die Dokumentation gleichzeitig zu reviewen. Wenn eine Anpassung der Dokumentation nicht stattgefunden hat, fällt dies auf und kann besprochen werden.

Fehlende, falsche oder unvollständige Dokumentation ist ein Bug

Eine direkte Konsequenz ist, dass unklare, fehlende oder falsche Dokumentation als Änderung oder Fehler angesehen wird und als solche zu behandeln sind. Das bedeutet, dass wir im Sprint einen Bug hinzufügen, um Informationen zu korrigieren und eine Story zur Erweiterung der Dokumentation um Aspekte, die wir vorher nicht berücksichtigt haben oder um deren Dokumentation wir gebeten wurden. Fehlende Dokumentation ist eine technische Schuld.

Der Nachteil dabei ist, dass wir eine neue Version der Dokumentation haben, die das gleiche Software-Artefakt beschreibt. Es ist nur in den Commits oder im Change-Log zu sehen, dass sich lediglich die Dokumentation geändert hat. Die Release-Notes werden diesen Umstand jedoch klarstellen, sodass Anwender keine falschen Erwartungen mit der neuen Software-Version verbinden.

Wir sollten dennoch dafür sorgen, dass dies nur selten oder bestenfalls nie passiert.

Don’t repeat yourself: Reusability für Dokumentation

Wir planen, das DRY-Prinzip, eine allgemeine Regel für gutes Softwaredesign, auf die Dokumentation anzuwenden.

Das bedeutet, dass wir, wenn eine Information in einer Quelle verfügbar ist, auf diese Quelle verweisen und die Information nicht als Kopie in unsere Dokumentation aufnehmen. Dies gilt insbesondere für sich ändernde Informationen, wie z. B. Konfigurationsoptionen für die Umgebung oder Namenslisten usw. Um dem Aktualisierungsdruck unserer Dokumentation zu vermeiden, verlassen wir uns darauf, dass die Quelle, auf die wir verweisen, die für unsere Version korrekte ist.

AsciiDoc unterstützt dieses Vorgehen, indem es auch Teile von anderen Dateien importieren kann:

Dokumentation durch Importieren aus dem Quelltext aktuell halten

Über die include-Direktive kann ein ander Datei eingefügt werden. Hier ein YAML File:

code beispiel
code beispiel

Und hier der asciidoc code:

code beispiel
code beispiel

Wenn die Wahrheit, wie so oft, im Quelltext liegt, sollte dieser auch in der Dokumentation genutzt werden. JavaDoc ist dazu leider nicht geeignet, da es über das Doclet nur einen speziellen Typ von Dokumentation liefert. AsciiDoctor kann allerdings Teile von beliebigen Textdateien inkludieren, indem dort Tags als Markierung verwendet werden.

code beispiel
code beispiel

Mit Hilfe des AsciiDoc Snippets

code beispiel
code beispiel

Kann der Ruby Code gezielt partiell extrahiert werden:

code beispiel
code beispiel

Das eignet sich glänzend, um Konstanten, Metriken, Messpunkte, Parameter, die im Code lesbar vorliegen, direkt in die Dokumentation zu übernehmen. So ist die Dokumentation immer auf dem Stand des Quelltextes und Tippfehler sind ausgeschlossen.

Release Notes

Ein weiteres Beispiel für automatisierte Dokumentation sind Release Notes. Durch ein wenig Commit-Disziplin und die Auswertung des Backlogs in Jira lassen sich exzellente Release Notes herstellen, die automatisch generiert werden und keine zusätzliche Arbeit erfordern.

Die über git log --oneline extrahierte History ist bereits als Basis ausreichend. Durch ein Shell oder python Script wird daraus zusammen mit AsciiDoc eine wunderbare ReleaseNotes PDF oder Webseite, die jeden Config-Manager glücklich macht.

Config Reports

In einer guten Delivery Pipeline liegen die Versionen eines Releases vor. Dort kann der Config-Management Report ansetzen und im Release-Build die Versionen auslesen und in die Form bringen, die der Configuration-Manager benötigt. Auch hier sind python und asciidoc die Werkzeuge der Wahl.

Automatisch generierte Dokumentation

Die automatisch generierte Dokumentation bezieht die Quellen ein, die wir selbst nutzen, um uns zu informieren oder Informationen abzulegen.

Schnittstellen Spezifikationen

In der Vergangenheit wurden Schnittstellen oft über Excel-Dateien ausgetauscht. Technisch genauer, aber nur technisch, nicht inhaltlich, wurde es bei Type-Libraries, oder der Interface Definition Language (IDL). Später wurde SOAP mit WDSL beliebt.

Allen vorgenannten Lösungen gemein ist, dass der Schwerpunkt auf der technischen Implementierung einer festgelegten Spezifikation lag.

Mit der Einführung von Smart Bears Swagger, das zum OpenAPI Standard wurde, verlagerte sich der Schwerpunkt. Die technische Umsetzung einer mit OpenAPI beschriebenen Schnittstelle war nur ein Teil der Lieferung. Gleichzeitig wird aus der Definition ein Web-Interface mit Testdaten und Beispielaufrufen. Diverse Konverter werden entwickelt und natürlich gibt es auch einen OpenAPI-to-AsciiDoc Generator, der den Weg zu PDF ebnet.

Hier finden wir also eine technische Lösung, die eine moderne, deklarative Schnittstellenentwicklung ermöglicht. Gleichzeitig werden alle Dokumentationsbedürfnisse aus der gleichen Quelle erfüllt und ein komplettes self-service Entwicklerportal kommt auch noch mit dazu.

Quellensuche

Manch weitere Quelle wird sich in einem Projekt auftun, die dokumentationswürdige Informationen enthält. Die folgende Liste soll als Anregung dienen, wo noch Daten sind, die mit einfachen Mitteln zur Dokumentation genutzt werden können.

  • Konfigurationsoptionen: Importiert aus Konfigurationsdateien, Enums, Code-Klassen, Deployment-Deskriptoren, … usw.
  • Deployment-Optionen: Technische Deskriptoren wie values.yaml mit enthaltenen Kommentaren dienen als Dokumentation.
  • Testreports: In regulierten Umgebungen wichtig. Diese werden nach der Testdurchführung von Testreport-Speicherorten importiert. Insbesondere E2E-Tests. Unit-Testreports sind üblicherweise kein wichtiger Teil der Dokumentation, auch wenn das Passieren der Tests ein wichtiges Quality-Gate darstellt.
  • Anforderungen: Importiert oder verlinkt durch manuelle Referenz beim Schreiben des Tests und durch die Dokumentationsstruktur
  • Umgesetzte Features: Features werden manuell importiert oder bei der Erstellung der Dokumentation eines Features wird einmalig manuell eine Referenz erfasst.
  • Stories: Sind Features in Stories unterteilt, werden bei der Erstellung der Dokumentation manuell Referenzen auf die Story hinterlegt.
  • Versionshinweise: Generiert aus dem Change-Log in Git. Es ist erforderlich, im Release-Prozess für jede gelieferte Komponente zu wissen, welche Version die vorherige war.
    • Offene Bugs oder bekannte Probleme sind schwer zu beantworten. Man könnte sich auf das Backlog verlassen, aber die Quelle ist oft unsauber.
    • Risiken und Schwachstellen können aus einem Whitelisting importiert werden (nicht verlinken).
    • Installations- und Deinstallationsanweisungen sind ein statischer Teil der Release-Notes und sind Teil der Vorlage.
    • Migrationen, falls manuell erforderlich, werden während der Implementierung beschrieben und in den Versionshinweisen referenziert. Durch die Implementierung von automatischen Migrations-Schritten kann die Dokumentationserstellung deutlich vereinfacht werden.

CI/CD Arbeitsablauf

Die eigentlichen Werkzeuge zur Dokumentation werden in der Pipeline angewendet. Eine mögliche CI/CD Pipeline könnte so funktionieren.

Diagramm zu Erstellung von Dokumentation
Diagramm zu Erstellung von Dokumentation
Erstellen der Dokumentation während der Implementierung im Branch

Tools

In diesem Abschnitt werden Werkzeuge zur Dokumentations-Automatisierung aufgezeigt, die sich bewährt haben. Natürlich dreht sich die Welt weiter und die Liste ist nicht vollständig.

Textuelle Dokumentation

Das Werkzeug der Wahl ist hier AsciiDoc mit dem Asciidoctor Processor und den gewünschten Plugins (Website).

  • Ermöglicht das Schreiben komplexer, aufgeteilter Dokumente wie diesem
  • Erlaubt die Einbindung und Verweise auf externe Dokumente
  • Erlaubt die teilweise Einbindung von Quellcode-Dokumenten
  • Erlaubt mehrere Ausgabeformate (HTML 5, DocBook 5, Handbuchseiten, PDF, EPUB 3, …​)
  • Erlaubt die Einbindung von Grafiken
  • Gute Editor-Unterstützung in IntelliJ und Visual Code
  • Erlaubt die Erstellung von Diagrammen mit PlantUML, Graphviz, Diagramm und andere
    • Erfordert die Installation von Plugins und asciidoctor im Build-Image, Agent-Server oder auf dem Runner

Grafische Dokumentation

Hier gibt es eine Reihe von Werkzeugen, die in AsciiDoc eingebunden werden können.

  • Draw.IO
    • enthalten in Confluence
    • Kann verwendet werden, um Diagramme zu zeichnen, die manuell als SVG in das Repository importiert werden.
    • Das Diagramm wird in Confluence erstellt und als SVG in einem eingefrorenen Zustand in das Code Repository exportiert.
    • Keine Bearbeitungsmöglichkeiten in AsciiDoc.
    • Der Export als SVG kann die Draw.IO-Strukturen einbetten, um einen Re-Import in Draw.IO zu ermöglichen.
  • PlantUML
    • Plugin für Asciidoctor
    • Diagrammquelle ist Teil der Asciidoc-Datei.
    • Erzeugt schöne JSON-Diagramme
  • andere Diagrammwerkzeuge, die direkt unterstützt werden
    • Diagramm
    • Bytefield
    • blockdiag
    • nwdiag
  • Screenshots

Export nach Confluence

  • der Export nach Confluence ist mit dem confluence-publisher möglich

Export nach Artifactory

  • gradle: Veröffentlichung der Dokumentation als PDF- oder HTML-Archiv

Export nach Sharepoint

  • gradle: Kopieren nach Sharepoint ist eher eine Frage der Zugriffsrechte als eine Frage des Tools
  • curl: sharepoint hat eine HTTP-basierte API, die zum Hochladen von Dateien verwendet werden kann Microsoft Social Forum

Dokumentation zusammenstellen

  • gradle: Unterstützt asciidoctor plugin
  • asciidoctor: Unterstützt die direkte Erzeugung von asciidoc-Ausgabeformaten ohne gradle
  • jq, yq: Abfragen von Werten und Transformation von JSON und YAML in Text

Umgang mit Repository-übergreifender Dokumentation

Das Problem der Repository-übergreifenden Dokumentation ist offensichtlich, dass sie Aspekte beschreibt, die nicht nur im aktuellen Repository zu finden sind. Dies ist unschön, da es vorkommen kann, dass eine Änderung in einem Dienst eine Änderung in einem anderen Repository erfordert, um die Dokumentation zu aktualisieren.

Nach meiner Erfahrung ist dieser Aspekt akzeptabel, aber wenn eine Repository-übergreifende Dokumentation erforderlich ist, muss man sich damit auseinandersetzen, wie man auf die aktuelle Dokumentation “der anderen Seite” referenzieren kann.

Eine mögliche Implementierung könnte die Verwendung von Git-Submodulen sein, so dass die Dokumentation zwar zur Bearbeitung zur Verfügung steht, aber nicht notwendigerweise mit der Repository-Dokumentation verknüpft ist. Git-Submodule bringen jedoch eine Fülle von operativen Problemen mit sich, die ihre Verwendung erschweren. Sie sind eine ständige Fehlerquelle, wenn man sie nicht richtig versteht oder anwendet.

Fazit

Dokumentation als Code zu betrachten ist mehr als ein lohnendes Experiment. Die Tools sind vorhanden, auch wenn es noch keine standardisierten Workflows oder Blueprints gibt, an die man sich nur anflanschen muss.

Das Thema ist allerdings dauerhaft und jede Automatisierung, so kompliziert sie auch zu implementieren war, trägt sofort Früchte und macht Lust auf Mehr.

Green-Field Projekte, die mit diesem Ansatz starten, haben große Vorteile. Hier kann man die Dokumentation von Anfang an auf Automatisierung trimmen und aufbauen. Wenn nie Word-Monster aus der Entwicklung kommen, muss man sie auch niemandem abgewöhnen.

Aber auch in Brown-Field Umgebungen schlummern Optimierungen. Bereits kleine Dinge, wie das Zusammenstellen des Git Change-Log in einem Format, so dass es direkt per Copy&Paste aus dem Jenkins-Build in das propriertäre legacy Release-Management System hineinkopiert werden kann, vereinfacht und standardisiert die Aufgabe so weit, dass es nicht nur eine Person im Team kann.

Ich hoffe ich konnte mit diesem Artikel genug Inspriation geben, um die eigene Produkt-Dokumentation einer genaueren Prüfung zu unterziehen. Wer mehr wissen mag, findet inzwischen auch Literatur zum Thema, zum Beispiel Martraire, C: Living Documentation: Continuous Knowledge Sharing by Design (ca. 40€). Ich stehe auch gerne zum Erfahrungsaustausch bereit und im Rahmen der Practice Software-Architecture werden wir die Diskussion über eine CoP weiterführen.

Viel Spaß beim Dokumentation programmieren!

Autor

Thomas Strauß

senior solution architect