Docs as Code - Dokumentation mit Asciidoctor
In nahezu jedem halbwegs professionellen Projekt im Bereich der Softwareentwicklung müssen verschiedene Arten von Dokumenten erstellt, fortgeschrieben, versioniert und publiziert werden. Viele Unternehmen setzen hier zunächst auf klassische Schreibprogramme, wie z. B. Microsoft Word. Für viele Anwendungszwecke kommt man damit gut zurecht. Wenn es um technische Dokumentationen geht, zeigen sich hier jedoch schnell Grenzen:
- Wie wird Quellcode eingebettet und wie erfolgt ein Syntax-Highlighting?
- Womit werden Grafiken und Diagramme erstellt, wie werden diese im Dokument eingebettet und wo verbleibt das Original?
- Wie kann eine Dokumentation kollaborativ fortgeschrieben werden, ohne Konflikte bei der Bearbeitung zu erhalten?
- Wie werden Versionen verwaltet, und welche Version der Doku passt zu welcher Version der Software?
AsciiDoc
Asciidoctor
Asciidoctor ist eine Neuimplementierung des ursprünglich in Python geschriebenen Textverarbeitungstoos und wurde in Ruby erstellt. Im vorliegenden Artikel kommt es allerdings nicht zum Einsatz, denn wir arbeiten hier mit AsciidoctorJ.
AsciidoctorJ
AsciidoctorJ is the official library for running Asciidoctor on the JVM. Using AsciidoctorJ, you can convert AsciiDoc content or analyze the structure of a parsed AsciiDoc document from Java and other JVM languages.
https://github.com/asciidoctor/asciidoctorj
Eine Beispiel-dokumentation
Um uns mit den Prinzipien der Auszeichnungssprache und den Möglichkeiten der Konvertierung vertraut zu machen, schauen wir uns im Folgenden anhand eines DV-Konzepts eine Beispiel-Dokumentation eines Software-Projektes an. Zunächst gehen wir auf die Strukturierung des Projektes und der Dateien ein. Danach werfen wir einen Blick auf einige wichtige Syntax-Elementen von AsciiDoc. Im Anschluss folgt ein Überblick über die Erzeugung von Grafiken und Diagrammen. Zuletzt schauen wir uns die Konfiguration des Maven-Plugins und die Integration in den Build-Prozess an.
Strukturierung
Die nebenstehende Grafik zeigt ein klassisches Java-Maven-Projekt. Unter src/main/java
befindet sich der Java-Quellcode - das sollte uns vertraut vorkommen. Etwas weniger bekannt dürfte allerdings das Verzeichnis src/docs/asciidoc
sein. Dort finden wir die *.adoc
-Dateien wieder, die den Quellcode für unsere Dokumentation enthalten. Wie diese inhaltlich aufgebaut sind, schauen wir uns im nächsten Kapitel an. Zunächst möchte ich die Strukturierung vorstellen.
Die Datei 1_main.adoc
ist das Hauptdokument, in das alle anderen Dokumente eingebunden sind. 2_preface.adoc
enthält Vorwort und Einleitung und 3_overviews.adoc
enthält Projektglossar, Abkürzungsverzeichnis etc. Dazwischen kommen die eigentlichen Kapitel mit den spezifischen Inhalten. Diese sind zur besseren Übersicht im Unterverzeichnis chapter
abgelegt. Es gibt hier also drei Kapitel (001_demo_ditaa.adoc
, 002_demo_use_case.adoc
und 003_demo_sequenz.adoc
).
Darüber hinaus gibt es natürlich noch die pom.xml
für Maven und eine README.md
.
Syntax von AsciiDoc
Schauen wir uns zunächst ein paar Syntax-Elemente von AsciiDoc an, damit wir ein Gefühl dafür bekommen, wie die Sprache aufgebaut ist.
Überschriften
Eine Überschrift wird mit einen =
-Zeichen eingeleitet
= erste Ebene / Dokumententitel
Eine Überschrift mit einem =
-Zeichen ist die Hauptüberschrift für das gesamte Dokument. Die weiteren Gliederungspunkte werden mit weiteren =
-Zeichen erstellt:
== zweite Ebene
=== dritte Ebene
==== vierte Ebene
===== fünfte Ebene
Aufzählungen
Unsortierte Aufzählungen (Unordered List) werden mit dem *
-Zeichen eingeleitet:
* erster Punkt
** zweiter Punkt
*** dritter Punkt
Sortierte Aufzählungen (Ordered List) werden mit dem .
-Zeichen eingeleitet:
. erster Punkt
.. zweiter Punkt
... dritter Punkt
Tabellen
Tabellen werden ebenfalls mit einfachen Ascii-Zeichen abgebildet. Eine einfache Tabelle könnte wie folgt aussehen:
.Die beteiligten Komponenten
|===
| Browser | Der Browser läuft auf dem Client-PC oder einem mobilen Endgerät (Tablet, Smartphone etc.)
| Frontend | Das Frontend wird auf dem Server in der DMZ deployed und ist für das Rendering der GUI zuständig.
| Middleware | Die Middleware enthält die Business-Logik.
| Datenbank | Die Daten werden in der zentralen Datenbank gespeichert.
|===
Die erste Zeile mit dem führenden Punkt ist die Legende der Tabelle. Legenden können auch an anderen Stellen verwendet werden (z. B. bei Grafiken).
Mit der zweiten Zeile |===
wird die Tabelle eingeleitet. In der dritten Zeile werden die einzelnen Zellen durch das |
-Symbol getrennt. In der letzten Zeile wird die Tabelle mit ===|
beendet.
Textformatierungen
Einfache Formatierungen von Text können wie folgt abgebildet werden:
Dies ist ein *fettes*
Wort.
Dies ist ein _kursives_
Wort.
Dieses ist ein als `Code`
dargestelltes Wort.
Code-Blöcke
Quellcode wird oft nicht nur im Text, sondern als kompletter Block dargestellt. Dazu wird dieser in zwei Blöcken von ....
eingeschlossen:
[source,xml]
....
<element tag="value">text</element>
....
Über dem Block wird in eckigen Klammern definiert, welchen Inhalt der folgende Block hat. In diesem Fall liegt mit source
also Quellcode in xml
vor.
Eine ausführliche Erläuterung mit entsprechenden Beispielen zur Syntax ist auf der offiziellen Webseite von Asciidoctor (hier) zu finden.
Diagramme
Ditaa
Ditaa steht für "Diagrams Through Ascii Art" und erlaubt die Erstellung von einfachen Grafiken und Diagrammen mittels Ascii-Art. Im konkreten Demo-Projekt wird dies im Kapitel 001_demo_ditaa.adoc
demonstriert:
.Legende der Grafik [ditaa] .... +---------+ +------------+ +------------+ +-----------+ | | | | | | | | | Browser | | Frontend | | Middleware | | Datenbank | | | HTTP | | HTTP | | JDBC | | | +--------->+ +--------->+ +--------->+ | | | | | | | | | | cYEL| +------>| c06F| | c0F0| | cPNK| +---------+ | +-----+------+ +-----+------+ +-----+-----+ | | | : | | /-------+--\ v v | | +----------+ +----------+ | DMZ | | Logging | | Logging | | | | | | | \----------/ | {d}| | {d}| +----------+ +----------+ ....
Das Resultat sieht dann wie folgt aus:
PlantUML
Einen anderen Ansatz verfolgt PlantUML. Mit einer speziellen DSL lassen sich durch einen Beschreibungstext komplexe und anschauliche Diagramme generieren. Je nach Diagramm-Typ funktioniert das besser oder schlechter. Sequenzdiagramme sind beispielsweise sehr gut geeignet, da ein solches Diagramm einen relativ einfachen Aufbau hat, und sich daher sehr gut textuell beschreiben lässt. Ein einfaches Beispiel liefert das Kapitel 003_demo_sequenz.adoc
unses Beispiel-Projekts:
.Request über Schnittstellen vom Frontend über Middleware zur Datenbank [plantuml] .... participant Frontend as FE participant Middleware as MW participant Datenbank as DB FE -> MW: GET /kunden/4711 activate FE MW -> DB: "SELECT * FROM KUNDEN where KD_NR = '4711'" activate MW MW <-- DB: KD oder leeres ResultSet deactivate MW FE <-- MW: HTTP 200/400/500 deactivate FE note left Kunde als HTTP-Body oder Error im HTTP-Header end note ....
Ein weiteres Beispiel mit PlantUML zeigt uns das Kapitel 002_demo_use_case.adoc
. Dort wird ein Use-Case-Diagramm verwendet:
.Verwendung der Demo-Applikation durch den Mitarbeiter im Fachbereich [plantuml] .... actor "MA Fachbereich" as MA_FB node Browser node Frontend { file "NFS Mount" as NFS } usecase CMS MA_FB -do-> Browser: ""nutzt Demo-Applikation"" Browser -ri-> Frontend: ""ruft Frontend auf"" CMS -up-> Frontend: ""CMS-Daten + Konfiguration"" ....
Werfen wir auch hier einen Blick auf das Ergebnis:
Maven-Plugin
Nachdem wir jetzt die grundlegenden Eigenschaften und die Struktur der Beispiel-Dokumentation angeschaut haben, werfen wir nun einen Blick auf das Resultat bzw. das Maven-Plugin von AsciidoctorJ, mit welchem der Output erzeugt wird.
Zunächst wird das Plugin in den build
-Block der pom.xml
eingebunden:
<build> <plugins> <plugin> <groupId>org.asciidoctor</groupId> <artifactId>asciidoctor-maven-plugin</artifactId> <version>${asciidoctor-maven-plugin.version}</version> <dependencies> <dependency> <groupId>org.asciidoctor</groupId> <artifactId>asciidoctorj</artifactId> <version>${asciidoctorj.version}</version> </dependency> <dependency> <groupId>org.asciidoctor</groupId> <artifactId>asciidoctorj-pdf</artifactId> <version>${asciidoctorj-pdf.version}</version> </dependency> <dependency> <groupId>org.asciidoctor</groupId> <artifactId>asciidoctorj-diagram</artifactId> <version>${asciidoctorj-diagram.version}</version> </dependency> </dependencies> <configuration> <sourceDirectory>src/docs/asciidoc</sourceDirectory> <preserveDirectories>true</preserveDirectories> <attributes> <sourcedir>${project.build.sourceDirectory}</sourcedir> </attributes> <requires> <require>asciidoctor-diagram</require> </requires> </configuration> <executions> <execution> <id>output-pdf</id> <phase>generate-resources</phase> <goals> <goal>process-asciidoc</goal> </goals> <configuration> <backend>pdf</backend> <attributes> <source-highlighter>coderay</source-highlighter> <icons>font</icons> <pagenums /> <toc /> <idprefix /> <idseparator>-</idseparator> </attributes> </configuration> </execution> <execution> <id>output-html</id> <phase>generate-resources</phase> <goals> <goal>process-asciidoc</goal> </goals> <configuration> <backend>html5</backend> <attributes> <source-highlighter>coderay</source-highlighter> <icons>font</icons> <pagenums /> <toc /> <idprefix /> <idseparator>-</idseparator> </attributes> </configuration> </execution> </executions> </plugin> <plugins> <build>
In den Zeilen 4-6 erfolgt die Angabe des Plugins org.asciidoctor:asciidoctor-maven-plugin:2.1.0
. Anschließend folgen die für das Plugin notwendigen Abhängigkeiten:
- asciidoctorj
- asciidoctorj-pdf
- asciidoctorj-diagram
In den Blöcken configuration
und exectutions
folgen dann konkrete Anweisungen an das Plugin. Dort sehen wir auch, dass es zwei Output-Formate gibt: PDF und HTML5. Im Rahmen des Build-Prozesses werden also Dokumente im PDF-Format und HTML5-Seiten erzeugt.
Um ein Gefühl dafür zu bekommen, wie die erzeugte Dokumentation aussieht, hier ein Auszug aus dem Kapitel 2 des PDF-Dokuments:
PDF eignet sich natürlich gut dafür, eine Gesamtdokumentation zusammen mit dem Software-Paket an einen Kunden auszuliefern, oder an Stakeholder zu verschicken.
Die HTML-Variante kann sehr einfach auf einem Webserver publiziert werden. Wenn dies im Rahmen eines automatischen Build-Prozesses, z. B. im Zuge des CI/CD-Prozesses erfolgt, dann ist sichergestellt, dass immer eine aktuelle Dokumentation zur Verfügung steht. Je nach Art der Dokumentation und Applikation entweder im Intra- oder sogar im Internet.
Hier ebenfalls ein Auszug aus der erzeugten HTML-Dokumentation von Kapitel 2:
Fazit
AsciiDoc in Kombination mit Asciidoctor oder AsciidoctorJ ist eine gute Variante für die Erstellung von technischen Dokumentationen. Die einfache Erzeugung und native Einbindung von Diagrammen erlaubt eine einfache Anpassung und Weiterentwicklung der Dokumentation. Durch die Integration in ein beliebiges Java-Projekt und den entsprechenden Build-Prozess kann die Dokumentation auf Knopfdruck oder sogar vollkommen automatisch generiert werden. Durch ein Quellcodeverwaltungssystem wird die Dokumentation automatisch versioniert und kann zusammen mit dem Programmcode weiterentwickelt werden. Verschiedene Ausgabeformate erlauben ein konsumentengerechtes Format, ohne zu viel Aufwand in Layout und Formatierung investieren zu müssen.
Der Quellcode des Beispiel-Projekts kann auf GitHub heruntergeladen werden: https://github.com/trojava/asciidoctorj-ordix-blog-demo
Principal Consultant bei ORDIX
Bei Updates im Blog, informieren wir per E-Mail.
Kommentare