Markdown – einfach und vielseitig

Wer Text schreibt, kann dies mit unterschiedlichen Werkzeugen bewerkstelligen, vom WYSIWYG-Editor à la Word bis hin zum reinen Texteditor. Jede dieser Varianten wartet mit unterschiedlichen Vor- und Nachteilen auf.

Daneben hat in den vergangenen Jahren die Nutzung der Auszeichnungssprache Markdown zugenommen und diese an Beliebtheit gewonnen. Im Gegensatz zum What You See Is What You Get-Ansatz trennt Markdown die Struktur und Formatierung vom endgültigen Erscheinungsbild, indem es die Bedeutung des Inhaltes betont. Trotzdem lässt sich ein solcher Markdown-Text auch ohne weitere Kenntnisse problemlos lesen:

# Überschrift

Lorem *ipsum dolor sit amet*, consectetur, adipisci 
velit, ut aspernatur labore ad dolores quidem eos
architecto pariatur. Dolor asperiores commodi corrupti, 
vel dignissimos velit, **labore aliquip voluptatem**:

* Lorem
* Ipsum
* dolor

## Noch eine Überschrift

Lorem ipsum dolor sit amet:

> Sequi quasi mollit dolor cupiditate in.

Somit stört Markdown den Lesefluss nicht und enthält doch Informationen über die Struktur des Dokumentes. Doch wie genau wird Markdown geschrieben, genutzt und wo finden sich seine Einsatzgebiete?

Auszeichnungssprachen

Markdown wird den Auszeichnungssprachen zugeordnet. Bei solchen Auszeichnungssprachen (engl. Markup language), handelt es sich um eine Sprache, die zur Strukturierung, Formatierung und Kennzeichnung von Texten und Daten verwendet wird.

Eine solche Sprache ermöglicht es, Textinhalte mit zusätzlichen Informationen zu versehen, die deren Struktur und Darstellung definieren. Diese zusätzlichen Informationen werden in Form von Tags oder Markierungen eingefügt, die wiederum von anderen Programmen, z. B. Browsern interpretiert werden können.

Zu den bekanntesten Auszeichnungssprachen gehört HTML:

<html>
<head>
  <title>Beispielseite</title>
</head>
<body>
  <h1>Lorem Ipsum</h1>

  Lorem ipsum dolor sit amet.
</body>
</html>

Geschichte

Historisch gesehen geht die Entwicklung von Markdown auf das Jahr 2004 zurück, in welchem John Gruber und Aaron Swartz diese Entwicklung anstießen. Aaron Swartz hatte vorher mit atx eine eigene Auszeichnungssprache definiert, aus der unter anderem die Überschriften-Semantik in Markdown übernommen wurde.

Die Hauptidee hinter Markdown war es, eine einfache Möglichkeit zu schaffen, Text in HTML zu konvertieren, ohne dass der Nutzer umfangreiche HTML-Kenntnisse benötigt. Gruber und Swartz wollten damit eine Sprache schaffen, die leicht zu lesen und zu schreiben ist. John Gruber fasste dies mit der Aussage:

Markdown is intended to be as easy-to-read and easy-to-write as is feasible.

in der ursprünglichen Markdown-Spezifikation zusammen. Inspiriert wurde die Syntax und der Aufbau von Markdown von bereits vorher verwendeten Konventionen, wie der Textauszeichnung in E-Mails und anderen Auszeichnungssprachen wie Textile.

Neben der ursprünglichen Spezifikation wurde auch ein Perl-Skript mit dem Namen Markdown.pl entwickelt, welches Markdown in HTML konvertieren konnte. Das Skript und die dazugehörige Dokumentation wurden unter der 3-Klausel BSD-Lizenz veröffentlicht und sind damit freie Software. Die einfache Syntax und die Möglichkeit, Markdown-Dateien in verschiedenen Umgebungen zu verwenden, machten es schnell populär.

Ein wesentlicher Aspekt von Markdown ist seine Lesbarkeit. Die Syntax ist so gestaltet, dass der Text auch dann lesbar bleibt, wenn er nicht in HTML umgewandelt wird. Dies unterscheidet Markdown von anderen Auszeichnungssprachen wie LaTeX oder HTML, die ohne entsprechende Rendering-Tools oft schwer zu lesen sind. Diese Eigenschaft machte Markdown besonders attraktiv für Blogger, Autoren und Entwickler, die ihre Texte sowohl in Rohform als auch in gerenderter Form verwenden wollten.

Mit der Zeit entwickelte sich Markdown zu einem De-facto-Standard für Textformatierung im Web. Viele Blogging-Plattformen, Content-Management-Systeme und Plattformen wie GitHub begannen, Markdown zu unterstützen.

GitHub spielte eine entscheidende Rolle bei der Popularisierung von Markdown, indem es die Sprache für die Dokumentation von Projekten und das Schreiben von README-Dateien bzw. README.md-Dateien verwendete. Dies führte dazu, dass immer mehr Entwickler und Autoren Markdown in ihren Arbeitsabläufen integrierten.

Trotz seiner Popularität gab es keine offizielle Standardisierung von Markdown, was zu verschiedenen Dialekten und Implementierungen führte. Dadurch entstanden Kompatibilitätsprobleme, da verschiedene Systeme und Tools unterschiedliche Varianten von Markdown unterstützten. Um diesem Problem zu begegnen, wurde 2014 das Projekt CommonMark ins Leben gerufen. CommonMark zielt darauf ab, eine einheitliche Spezifikation für Markdown zu schaffen und so die Kompatibilität zwischen verschiedenen Implementierungen zu verbessern.

Nicht unerheblich für den Erfolg von Markdown war die Entwicklung von entsprechenden Konvertern. Software wie Pandoc ermöglichte es Benutzern, Markdown-Dokumente in verschiedene Formate zu konvertieren. Diese Werkzeuge erweiterten die Einsatzmöglichkeiten von Markdown erheblich, indem sie den Export von Markdown-Dokumenten in PDF-, Word- und andere Formate ermöglichten.

Die Flexibilität von Markdown führte zu seiner Verwendung in anderen Bereichen, wie z. B. in wissenschaftlichen Publikationen, technischen Dokumentationen und sogar in Präsentationen. Durch die Integration von Erweiterungen wie MathJax für mathematische Formeln konnte Markdown an die spezifischen Bedürfnisse verschiedener Benutzergruppen angepasst werden.

Syntax

Grundsätzlich handelt es sich um bei einem Markdown-Dokument um ein normales Textdokument, welches über verschiedene Zeichen strukturiert wird. So befinden sich im folgenden Dokument eine Überschrift der ersten Ebene und ein Text, in welchem ein Wort kursiv gestellt wird:

# Lorem Ipsum

Lorem Ipsum dolor *sit* amet.

In Markdown existieren verschiedene Arten von Blöcken, die zur Strukturierung und Formatierung von Text verwendet werden. Grundlegend können Blöcke in Markdown in zwei Typen unterteilt werden: Containerblöcke und Blattblöcke (engl. leaf blocks).

Containerblöcke dienen als übergeordnete Strukturen, die mehrere Elemente umfassen können. Blattblöcke hingegen sind Blöcke, die keine anderen Blöcke enthalten können. Sie sind die „Blätter“ der Dokumentstruktur und enthalten den eigentlichen Inhalt.

Zu den Containerblöcken gehören Absätze, Blockzitate, Listen und Codeblöcke. Zu den Blattblöcken gehören Überschriften, horizontale Linien, Inline-Code und HTML-Blöcke.

Eines der einfachsten Elemente in Markdown ist der Absatz. Dieser definiert sich als eine Ansammlung von Zeilen. Getrennt werden diese Absätze durch eine oder mehrere leere Zeilen. In der Denkweise von Markdown bedeutet dies, dass wenn die Zeile leer aussieht, sie leer ist. So würde eine Zeile gefüllt mit Leerzeichen oder Tabs als leer interpretiert werden.

Ein grundlegendes Merkmal von Markdown ist die Verwendung von Klartextzeichen, um Formatierungen zu definieren. Überschriften können etwa durch Voranstellen einer Raute erstellt werden.

Mit einer einzelnen Raute kann so eine Überschrift der ersten Ebene, mit zwei Rauten eine Überschrift der zweiten Ebene usw. definiert werden. Bei einer Konvertierung in HTML würde hierbei die Tags <h1> und <h2> generiert werden:

# Überschrift der ersten Ebene

## Überschrift der zweiten Ebene

### Überschrift der dritten Ebene

Diese Art der Überschriften wird auch atx-Überschrift genannt. Daneben werden in der ursprünglichen Markdown-Spezifikation auch Setext-Überschriften definiert. Setext-Überschriften werden durch das Unterstreichen des Überschriftentextes erzeugt:

Überschrift der ersten Ebene
============================

Überschrift der zweiten Ebene
-----------------------------

In der Praxis kommt heute zumeist die atx-Variante zum Tragen, mit welcher bis zu sechs Ebenen definiert werden können. Weniger bekannt ist, dass diese Art der Überschrift auch geschlossen existieren darf:

# Überschrift (Ebene 1) #

Lorem Ipsum dolor sit amet.

## Überschrift (Ebene 2) ##

Die Nutzung der schließenden Rauten ist hierbei rein kosmetischer Natur und hat sonst keinerlei Auswirkungen. Allerdings sollte beachtet werden, dass diese geschlossene Variante nur selten genutzt und von vielen Markdown-kompatiblen Werkzeugen in dieser Form nicht unterstützt wird.

Da Markdown ursprünglich zur Konvertierung in HTML gedacht war, dieses aber nicht ersetzen sollte, verfügt es über die Möglichkeit Inline-HTML zu nutzen:

# Hypergraphen

Ein Hypergraph ist eine Verallgemeinerung eines Graphen.

# Begrifflichkeiten

Folgende Begrifflichkeiten definieren einen solchen Graphen:

  <table>
        <tr>
            <th>Eigenschaft</th>
            <th>Beschreibung</th>
        </tr>
        <tr>
            <td>Knoten</td>
            <td>Die grundlegenden Einheiten eines Hypergraphen, ähnlich den Knoten in einem einfachen Graphen.</td>
        </tr>
        <tr>
            <td>Kanten</td>
            <td>Kanten in einem Hypergraphen, auch Hyperkanten genannt, können mehr als zwei Knoten verbinden.</td>
        </tr>
    </table>

Neben Hypergraphen ...

Sollen in Markdown Zeichen genutzt werden, welche durch die Markdown-Syntax vorbelegt sind, so müssen diese Zeichen maskiert werden. Dies geschieht mit dem Backslash:

\# Dies ist keine Überschrift

Für Hervorhebungen kennt Markdown die Möglichkeit, Text als fett und kursiv zu markieren. Um einen Text kursiv zu setzen, reicht es aus ihn in Sternchen zu setzen:

*kursiv*

Soll der Text hingegen fett gesetzt sein, so werden zwei Sternchen benötigt:

**fett**

Auch die Kombination aus Kursiv- und Fettschreibung ist möglich, indem drei Sternchen genutzt werden:

***kursivundfett***

Neben der Nutzung des Sternchens ist auch die Nutzung von Unterstrichen möglich. Allerdings wird dies in der Praxis seltener genutzt.

Neben diesen einfachen Formatierungen sind in Markdown Blöcke wie Zitate und Beispielcodeblöcke möglich. So beginnt ein Zitat in Markdown mit einer spitzen Klammer:

> There is no reason for any individual to have a computer in his home.
> Ken Olsen, 1977

Hierbei ist auch erlaubt, diese Blöcke ineinander zu verschachteln, sodass verschachtelte Zitate dargestellt werden können:

> Er pflegte es immer mit einem Zitat zu begründen:
> > Wenn Sterne tanzen, ihre Glut sich erhebt.

Codeblöcke können in Markdown ebenfalls abgebildet werden. Dazu muss der entsprechende Code mit vier Leerzeichen bzw. einem Tab eingerückt werden. Damit wird ein solcher Block als preformatierter Text betrachtet.

Alternativ kann ein Codeblock auch über drei Backticks erzeugt werden:

```
int number = 13052025;

if(isPrime(number)) {
    ...
}
```

Markdown unterstützt Listen. Hierbei wird zwischen ungeordneten und geordneten Listen unterschieden. Ungeordnete Listen können mit einem Sternchen erzeugt werden:

# Einkaufsliste

* Brot
* Marmelade
* Salat

Daneben können solche Listen auch mit einem Plus- oder einem Minus-Zeichen angelegt werden.

Für geordnete Listen muss eine Zahl vor den eigentlichen Listenpunkt geschrieben werden:

# Prioritäten

1. Rasen mähen
2. Einkaufen
3. Kochen

Die Zahlen zur Nummerierung müssen nicht unbedingt aufeinanderfolgen; dies dient nur der besseren Lesbarkeit. In der Theorie könnte eine solche Liste auch wie folgt aussehen:

# Prioritäten

1. Rasen mähen
1. Einkaufen
1. Kochen

Würde ein solches Markdown-Element in eine HTML-Datei konvertiert werden, so würde ein Dokument aus einem <ol>-Tag mit einer entsprechenden Liste bestehen. Die Nummern würden in diesem Fall bei der Konvertierung entfallen.

Markdown ermöglicht auch das Einfügen von horizontalen Linien, die als Trennlinien verwendet werden können. Dies geschieht durch mindestens drei Bindestriche, Sternchen oder Unterstriche in einer separaten Zeile. Diese Trennlinien sind nützlich, um verschiedene Abschnitte eines Dokumentes visuell und thematisch zu trennen.

Neben Formatierungen können in Markdown auch Verlinkungen und Bilder integriert werden. Ein Link wird durch eckige Klammern für den Linktext und runde Klammern für die URL definiert:

[Linktext](http://example.com)

Diese Links werden auch Inline-Links genannt. Markdown ermöglicht daneben, Links auf eine elegantere Weise zu verwalten, insbesondere wenn dieselbe URL mehrfach verwendet wird. Dies geschieht durch die Verwendung von Referenz-Links. Ein Referenz-Link wird in zwei Teilen geschrieben: Der erste Teil enthält den Link-Text und eine Referenz in eckigen Klammern:

[Beispiel-Link][1]

Nun muss dazu die entsprechende Referenz definiert werden:

[1]: https://www.example.com

Diese Methode verbessert die Lesbarkeit des Quelltextes und erleichtert die bessere Verwaltung von Links, da die URL nur einmal geändert werden muss, wenn sie aktualisiert wird.

Neben der Verlinkung zu externen Webseiten ermöglicht Markdown auch das Verlinken zu anderen Teilen desselben Dokumentes, was besonders nützlich für lange Texte oder Dokumentationen ist. Dies wird durch die Verwendung von Anker-Links erreicht. Ein Anker-Link verweist auf eine bestimmte Überschrift im Dokument. Beispielhaft könnte dies so aussehen:

[Einleitung](#einleitung)

Damit würde dieser Link auf die Überschrift Einleitung verweisen.

Eine eher selten genutzt Möglichkeit der Verlinkung sind sogenannte Autolinks. Damit können URLs und E-Mail-Adressen automatisch in Links umgewandelt werden. Dazu muss die betreffende URL oder E-Mail-Adresse in spitze Klammern gesetzt werden:

<example.com>

Die Syntax zur Einbindung von Bildern ähnelt der von Verlinkungen. Jedoch wird ein Ausrufezeichen vor der Definition genutzt:

![Alt-Text](http://example.com/bild.jpg)

Auch die Angabe eines Titels ist bei dieser Art der Definition möglich:

![Alt-Text](http://example.com/bild.jpg "Titel des Bildes")

Daneben sind wie bei der Verlinkung auch bei der Definition von Bildern die Möglichkeiten von Referenzen gegeben.

Neben den klassischen Elementen, die in Markdown dargestellt werden können, existieren auch Elemente, welche durch verschiedene Erweiterungen bzw. Varianten, wie GitHub Flavored Markdown, zu Markdown kamen.

In diesen Erweiterungen können unter anderem Tabellen definiert werden. Tabellen können erstellt werden, indem Spalten durch senkrechte Striche und Zeilen durch Zeilenumbrüche getrennt werden. Die Kopfzeile wird durch eine Trennlinie aus Bindestrichen unterstrichen. Diese Syntax macht es einfach, strukturierte Daten darzustellen.

Eine solche Tabelle könnte beispielhaft wie folgt aussehen:

| Spalte 1 | Spalte 2 | Spalte 3 |
|----------|----------|----------|
| Inhalt 1 | Inhalt 2 | Inhalt 3 |
| Inhalt 4 | Inhalt 5 | Inhalt 6 |

Auch eine Syntax für Fußnoten ist im ursprünglichen Markdown nicht vorgesehen, wurde aber in unterschiedlichsten Varianten definiert:

Das ist ein Beispieltext mit einer Fußnote.[^1]

[^1]: Dies ist der Text der Fußnote.

Komplexer wird es bei der Integration von mathematischen Formeln in Markdown. Hier sind unterschiedliche Möglichkeiten gegeben, wie die Nutzung von MathJax oder direkte Unterstützung der LaTeX-Syntax für Formeln, die allerdings nur in bestimmten Varianten und Markdown-Werkzeugen unterstützt werden.

Geschmacksrichtungen

Standard-Markdown, oft einfach Markdown genannt, ist die ursprüngliche Version, die von John Gruber veröffentlicht wurde. Es bietet grundlegende Formatierungsoptionen wie Überschriften, Listen, Links, Bilder und Zitate.

Daneben existieren Markdown-Varianten, welche unterschiedlichste Formatierungsmittel und Möglichkeiten hinzufügen. Diese Varianten erweitern die ursprüngliche Markdown-Syntax und bieten zusätzliche Funktionen, um den unterschiedlichen Anforderungen der Benutzer gerecht zu werden. Jede Variante hat ihre eigenen spezifischen Anwendungsfälle und wird in verschiedenen Kontexten bevorzugt.

Zu den häufigsten Varianten zählen GitHub Flavored Markdown, CommonMark, Markdown Extra, MultiMarkdown und die Pandoc-Markdown-Variante, wobei CommonMark im Verlauf des Artikels noch separat betrachtet werden soll.

Varianten unter der Lupe

GitHub Flavored Markdown ist eine erweiterte Version von Markdown, die von GitHub entwickelt wurde. Sie fügt zusätzliche Funktionen hinzu, die speziell auf die Bedürfnisse von Entwicklern und die Nutzung auf GitHub zugeschnitten sind. Zu den Erweiterungen gehören Tabellen, erweiterte Listen, Inline-Code, Codeblöcke mit Syntaxhervorhebung und Task-Listen.

Markdown Extra ist eine Erweiterung, die von Michel Fortin entwickelt wurde. Es fügt zusätzliche Funktionen wie Definition Lists, Fußnoten, Abkürzungen und Tabellen hinzu.

MultiMarkdown wurde von Fletcher Penney entwickelt und erweitert die Fähigkeiten von Markdown um Funktionen wie Tabellen, Fußnoten, Referenzen und mathematische Unterstützung. Es ist besonders nützlich für wissenschaftliche und technische Dokumentationen.

Neben diesen Varianten existieren weitere Markdown-Varianten, wie RMarkdown und kramdown, welche hier allerdings nicht weiter behandelt werden sollen.

Standardisierung

Die ursprüngliche Markdown-Spezifikation von John Gruber kämpft mit einigen Mehrdeutigkeiten. Daneben wurden im Laufe der Zeit, wie oben beschrieben, eigene Varianten und Erweiterungen von Markdown entwickelt. Diese Varianz führte zu Problemen beim Teilen und Verarbeiten von Markdown-Dokumenten.

Im Jahr 2012 initiierte eine Gruppe von Personen, zu der Jeff Atwood und John MacFarlane gehörten, eine Standardisierungsinitiative. Eine Community-Website wurde erstellt, um eine Vielzahl von Werkzeugen und Ressourcen zu dokumentieren, die Autoren von Dokumenten und Entwicklern verschiedener Markdown-Implementierungen zur Verfügung stehen sollten.

Im September 2014 äußerte Gruber Bedenken hinsichtlich der Nutzung des Namens Markdown für diese Initiative, woraufhin sie in CommonMark umbenannt wurde.

CommonMark veröffentlichte mehrere Versionen einer Spezifikation, einer Referenzimplementierung und einer Testsuite und plant eine endgültige 1.0-Spezifikation vorzustellen. Diese 1.0-Spezifikation wurde jedoch bisher nicht veröffentlicht, da noch wichtige Probleme ungelöst sind.

Einige Projekte haben mittlerweile die Definition von CommonMark übernommen darunter Discourse, GitHub, und Stack Exchange.

Vom CommonMark-Projekt werden unterschiedlichste Parser angeboten, wie commonmark-java, welche wiederum Erweiterungen unterstützen. Daneben existieren andere Parser, welche ebenfalls die CommonMark-Spezifikation implementieren, z. B. markdown-it.

Auch wenn sich CommonMark in vielen Bereichen durchgesetzt hat, ist die Vielfalt und Unterschiedlichkeit der Markdown-Derivate, schon im Ursprung von Markdown angelegt, neben den anderen Problemen, welche oft mit der Definition eines Standards eingehen.

RFCs

Daneben fand Markdown auch bereits Erwähnung in einigen RFCs. Im März 2016 wurden zwei relevante RFCs veröffentlicht: RFC 7763 führte den MIME-Typ text/markdown ein, und RFC 7764 diskutierte unter anderem die Varianten MultiMarkdown, GitHub Flavored Markdown, Pandoc und Markdown Extra.

Markdown in der Praxis

Doch wie sieht die Nutzung von Markdown in der Praxis aus? Hier haben sich in den vergangenen Jahren viele Gebiete gefunden, in denen Markdown genutzt wird.

Texteditoren und IDEs

Viele Entwicklungsumgebungen und Texteditoren unterstützen Markdown mittlerweile von Haus aus. Dies bedeutet meist ein (optionales) Rendering und eine Hervorhebung der Formatierungselemente, wie bei der Fett- und Kursivstellung von Texten. Im Rahmen von Textdateien wird als Endung für Markdown-Dateien überwiegend die Endung .md genutzt.

Markdown-Editor in IntelliJ IDEA

So unterstützen IDEs wie die JetBrains IDEs und Editoren wie Atom, Visual Studio Code oder auch Texteditoren wie Notepad++, Sublime Text oder TextMate Markdown.

Markdown-Unterstützung in TextMate

Daneben existieren mit Editoren wie MarkText, Anwendungen welche speziell auf Markdown geeicht sind. Dieser Editor bietet eine Echtzeit-Vorschau, Unterstützung für CommonMark und GitHub Flavored Markdown sowie eine Vielzahl von Themes und Tastenkombinationen.

Zusätzlich zu den beschriebenen Texteditoren existieren auch webbasierte Markdown-Editoren wie Dillinger.

Der Markdown-Editor Dillinger

Auch dieser Editor bietet eine Echtzeit-Vorschau und die Möglichkeit, Dokumente in unterschiedliche Formaten zu exportieren.

Notiz-Applikationen

Neben reinen Texteditoren und IDEs haben sich mittlerweile auch viele Notiz-Applikationen für Markdown erwärmt.

Während die Unterstützung bei Apps wie Evernote und OneNote eher eingeschränkt ist, oder nur durch Plugins ermöglicht wird, existieren andere Applikationen wie Bear, Joplin oder Obsidian, die sich weitgehend auf Markdown stützen.

Joplin nutzt Markdown als Basis

Markdown dient hier als schneller und unkomplizierter Weg, Informationen zu erfassen. Je nach Applikation werden unterschiedliche Ansichten auf die Markdown-Dokumente geliefert, wie zum Beispiel das Quelldokument und das entsprechende Rendering. Bei Joplin werden auch Webseiten in Markdown konvertiert, wenn sie mit dem Webclipper gespeichert wurden.

Blogging und Content Management

Viele Blogging-Plattformen wie WordPress, Ghost und Jekyll unterstützen Markdown, was es Autoren ermöglicht, sich auf das Schreiben zu konzentrieren, ohne sich um die Formatierung zu sorgen.

Da Markdown-Dateien ursprünglich darauf angelegt waren, einfach in HTML umgewandelt zu werden, vereinfacht dies die Veröffentlichung im Web.

Je nach verwendetem System werden hier, wie im Falle von WordPress, Plugins für die Unterstützung benötigt. Andere Systeme wie Ghost und Jekyll unterstützen Markdown nativ.

Dokumentation und technisches Schreiben

Besonders beliebt ist Markdown in der Softwareentwicklung für die Erstellung von Dokumentationen.

Plattformen wie GitHub verwenden Markdown für README-Dateien, die Projektdetails und Anweisungen enthalten. Mit Markdown können Entwickler schnell und effizient Dokumentationen erstellen und aktualisieren.

# Java Starter Project

Starter project for Java based on Maven. Generates a fat JAR file containing all dependencies. JAR files are created with:

> mvn package

## Dependencies

Includes some basic dependencies:

* Guava
* GSON
* SLF4J
* JUnit (Version 5)

...

Neben der Dokumentation in Softwareprojekten existieren eine Reihe von Dokumentationstools.

Eine aus Markdown erzeugte Mkdocs-Dokumentation

So setzen Werkzeuge wie MkDocs und Sphinx auf Markdown und auch Plattformen wie ReadTheDocs unterstützen Markdown.

E-Mails und Kommunikation

Markdown kann zum Schreiben von E-Mails verwendet werden, um Text klar und strukturiert zu formatieren. Einige E-Mail-Clients unterstützen Markdown direkt. So existieren Clients wie MailMate, die Markdown nativ zum Schreiben von E-Mails unterstützen.

Auch etablierte Mail-Clients wie Thunderbird können über Add-Ons wie Markdown Here mit einer entsprechenden Funktionalität nachgerüstet werden.

Präsentationen

Mittels entsprechender Frameworks und wie reveal.js können auch Präsentationen über Markdown erstellt werden.

Reveal.js ist ein Open-Source-Framework zur Erstellung von Präsentationen im Webbrowser. Entwickelt von Hakim El Hattab, ermöglicht es Nutzern, ansprechende und interaktive Präsentationen mit HTML, CSS und JavaScript, aber auch mit Markdown zu gestalten.

Dadurch kann sich der Ersteller einer Präsentation auf die Inhalte konzentrieren, ohne sich mit Designfragen auseinandersetzen zu müssen.

Eine reveal.js Präsentation

Dazu müssen die Markdown-Dateien nur innerhalb der Index-Datei der reveal.js-Präsentation eingebunden werden:

<div class="slides">
    <section data-markdown="markdown/intro.md"
				data-separator="^-----\n"
				data-separator-vertical="^---\n"
				data-separator-note="^Note:"
				data-charset="utf-8">
	</section>
	<section data-markdown="markdown/webservices.md"
				data-separator="^-----\n"
				data-separator-vertical="^---\n"
				data-separator-note="^Note:"
				data-charset="utf-8">
	</section>

...

Aussehen würde eine beispielhafte Slideabfolge einer Sektion dabei wie folgt:

## OpenAPI

aka Swagger

Note:
* maschinenlesbare Interfacedefinitionen
* Contract-First-Gedanke
* betreut von der OpenAPI Initative

---

![OpenAPI Initiative](images/openapi.png)

Note:
* Atlassian
* Google
* Paypal
* SAP

...

Damit lassen sich über Markdown schnell Präsentationen erzeugen, welche den Fokus auf den Inhalt, anstelle der mühsamen Gestaltung legen.

Schreiben

Neben den vorgestellten Texteditoren, existieren eine Reihe von Werkzeugen, welche sich auf den Aspekt des Schreibens längerer Werke, mittels Markdown konzentrieren.

So existiert mit iA Writer ein minimalistischer Texteditor, der sich besonders an Autoren, Journalisten und andere Schreibende richtet, die eine ablenkungsfreie Umgebung schätzen.

Speziell zu iA Writer existieren Open Source-Alternativen, wie FocusWriter, welche sich ebenfalls ablenkungsfreies Schreiben auf die Fahnen geschrieben haben.

Ulysses

Eine weitere auf Markdown zentrierte Schreibanwendung ist Ulysses, die speziell für Autoren und Schriftsteller entwickelt wurde. Sie bietet eine ablenkungsfreie Benutzeroberfläche und eine Vielzahl von Werkzeugen, die das Schreiben und Organisieren von Texten erleichtern.

Ulysses unter macOS

Die App basiert auf Markdown, und die erzeugten Dokumente können in unterschiedliche Ausgabeformate exportiert werden.

Kollaboratives Schreiben

Neben dem Schreiben als Einzelperson existieren etliche Werkzeuge für kollaboratives Schreiben, wie zum Beispiel die unterschiedlichsten Varianten von EtherPad. Mit HedgeDoc existiert ein solcher webbasierter Editor mit Markdown-Unterstützung.

HedgeDoc als kollaborativer Markdown-Editor

Ursprünglich als CodiMD bekannt, bietet die Anwendung eine benutzerfreundliche Oberfläche, die sowohl für Einzelpersonen als auch für Teams geeignet ist. Die Markdown-Unterstützung orientiert sich an CommonMark und dem GitHub Flavored Markdown.

Zettlr

Zettlr ist eine freie Software, die darauf abzielt, das Schreiben und Verwalten von Texten zu unterstützen. Hier liegt der Fokus auf wissenschaftlichem Arbeiten. Die Anwendung bietet Funktionen zur Erstellung von Markdown-Dokumenten und zur Organisation von Notizen.

Zettlr unter macOS

Zudem ist sie mit Referenzverwaltungstools wie Zotero kompatibel, was die Verwaltung von Literaturquellen erleichtert. Zettlr ermöglicht den Export von Dokumenten in verschiedene Formate wie PDF und Word.

Im weiten Web

Grundsätzlich findet sich Markdown-Unterstützung in vielen webbasierten Systemen, wie Wikis, Diskussionsplattformen und vielen weiteren.

Foren wie Reddit und Stack Overflow unterstützen Markdown, um Benutzern das Formatieren ihrer Beiträge zu erleichtern. Durch die einfache Syntax können auch Nutzer ohne größere technische Vorkenntnisse ihre Beiträge sinnvoll gestalten.

Konverter

Neben dem Schreiben in Markdown ist oft auch der Export in andere Formate gewünscht. Während viele Applikationen dies von sich aus beherrschen, gibt es auch spezialisierte Software wie Pandoc, für solche Zwecke.

Pandoc ist ein Werkzeug zur Konvertierung von Dokumenten zwischen verschiedenen Formaten. Es unterstützt die Konvertierung von Markdown in HTML, PDF, DOCX, LaTeX und viele andere Formate.

Pandoc nutzt hierbei seinen eigenen Markdown-Dialekt und ist freie Software.

Ressourcen und Dokumentation

Neben Dokumenten wie der ursprünglichen Spezifikation und CommonMark existieren es eine Reihe von Ressourcen, die in Markdown einführen, wie der Markdown Guide.

Dieser bietet eine umfangreiche Ressource rund um Markdown, führt in die Syntax ein und pflegt eine Liste von Markdown-Tooling.

Auch existieren unzählige Cheat Sheets und Tutorials für Markdown und ermöglichen es Einsteigern schnell in der Markdown-Welt anzukommen.

Fazit

Markdown wurde ursprünglich mit einem minimalistischen Ansatz entwickelt und hat sich schnell eine breite Anhängerschaft aufgebaut. Während die unterschiedlichen Varianten etwas Verwirrung stiften können, ist der Kern von Markdown wohl definiert.

Selbst ohne spezielle Tools lässt sich Markdown problemlos lesen und verstehen, was es ideal für die Erstellung von Dokumentationen, Notizen und Texten macht.

Mittels Markdown können elegant und schnell Texte geschrieben werden, ohne dass sich in Formatierungsoptionen und Designfragen verloren wird. Damit bietet es im Zusammenhang mit entsprechenden Applikationen eine ablenkungsfreie und effiziente Schreibumgebung.

Überdies bietet Markdown bzw. die Werkzeuge rund um Markdown die Flexibilität, ansprechend formatierte Dokumente zu exportieren. Diese Kombination aus Einfachheit und Vielseitigkeit machte Markdown zu einem unverzichtbaren Werkzeug.

Neben dem reinen Schreiben hat sich Markdown darüber hinaus viele weitere Anwendungsgebiete erobert und wird uns sicherlich auch in Zukunft begleiten.

Dieser Artikel erschien ursprünglich auf Golem.de und ist hier in einer alternativen Variante zu finden.

EPUB aus einem mdBook erstellen

Das Community-Buch über Rust (deutsche Version), wird als mdBook gepflegt. Damit ist es möglich dieses als Webseite auszugeben. Allerdings war ich auf der Suche nach einer Möglichkeit unkompliziert ein EPUB aus einem mdBook zu generieren. Fündig geworden bin ich bei einem Backend, welches diese Funktionalität zur Verfügung stellt. Dieses muss im ersten Schritt über den Rust-Paketmanager Crates installiert werden:

cargo install mdbook-epub

Anschließend kann in das gewünschte mdBook-Projekt gewechselt werden und dort das E-Book erzeugt werden:

mdbook-epub --standalone true .

Dieses wird im im Ordner book bereitgestellt und kann dort weitergenutzt werden.

Shelly Plug S mit HomeKit-Unterstützung nachrüsten

Der Shelly Plug S unterstützt, wie andere Shelly-Geräte, von sich aus kein HomeKit. Allerdings existiert eine alternative Firmware, über welche diese Unterstützung nachgerüstet werden kann.

Der Shelly Plug S

Zur Installation muss ermittelt werden, unter welcher IP-Adresse der Shelly Plug S erreichbar ist. Diese wird im Browser aufgerufen und anschließend sollte ein Update durchgeführt werden.

Die Firmware sollte auf die aktuelle Version geflasht werden

Ist dies geschehen, kann die Installation der alternativen Firmware durchgeführt werden. Dazu wird die IP-Adresse des Shelly Plug S mit einem neuen Parameter aufgerufen:

http://192.168.1.42/ota?url=http://rojer.me/files/shelly/shelly-homekit-ShellyPlugS.zip

Es wird anschließend ein JSON ausgegeben:

{„status“:“updating“,“has_update“:false,“new_version“:“20230913-113421/v1.14.0-gcb84623″,“old_version“:“20230913-113421/v1.14.0-gcb84623″,“beta_version“:“20231107-164219/v1.14.1-rc1-g0617c15″}

Nach etwa einer bis zwei Minuten ist das Firmware-Update komplett und eine neue Oberfläche erscheint, beim Aufruf der IP-Adresse im Browser.

Die neue Oberfläche

Mit der neuen Firmware kann der Shelly Plug S als HomeKit-Gerät eingebunden werden. Dazu muss der Setup-Button in der Weboberfläche aktiviert werden. Anschließend kann das Gerät über die Home-App unter iOS hinzugefügt werden. Es ist auch möglich, die Factory-Firmware wieder aufzuspielen, sodass der Shelly Plug S wieder wie gewöhnlich genutzt werden kann.

Fluent Interfaces unter Java

Der Begriff des Fluent Interface hat mittlerweile knapp zwei Jahrzehnte auf dem Buckel und solche Schnittstellen sind mittlerweile auch in größerem Umfang in der Praxis angekommen und werden dort vielfältig genutzt. Trotzdem scheint es manchmal schwer zu fallen genau zu definieren, was ein solches Fluent Interface ist, was es auszeichnet und wie es in der Praxis sinnvoll genutzt werden kann.

Herkunft

Fluent Interfaces, welche wohl holprig mit einer fließenden Schnittstelle übersetzt werden könnten, sind eine Begrifflichkeit, welche in dieser Form erstmals 2005 von Martin Fowler und Eric Evans definiert wurden.

Martin Fowler ist bekannt für seine Arbeit, am Manifest für Agile Softwareentwicklung und seine Bücher, welche unter anderem das Code-Refactoring in die breite Öffentlichkeit trugen und populär machten.

Eric Evans ist vorwiegend für seine Beiträge rund um das Domain-Driven Design bekannt, dessen Gedanken er erstmals im gleichnamigen Buch Anfang der 2000er-Jahre zusammenfasste und somit den Begriff prägte.

Sinnvoller wäre für Fluent Interfaces allerdings die Bezeichnung als sprechende Schnittstelle, welcher eher der Idee im Kern entspricht. Bezugnehmend auf die Wortherkunft aus dem englischen to be fluent in a language, kann allerdings auch im Deutschen von Fluent Interfaces gesprochen werden.

Ideen des Fluent Interfaces

Dem Namen entsprechend ist eines der Ziele eines Fluent Interfaces, APIs besser lesbar und verstehbarer zu gestalten. Daneben soll die API Funktionalitäten passend zum Objekt bereitstellen können.

Bei Betrachtung einer solchen sprechenden Schnittstelle, soll der Quellcode sich wie eine natürliche Sprache bzw. ein Text in einer solchen anfühlen, anstatt eine Reihe von abstrakten Anweisungen darzustellen. Martin Fowler definierte auch ein Maß für diese Fluidität:

The key test of fluency, for us, is the Domain Specific Language quality. The more the use of the API has that language like flow, the more fluent it is.

Ein schönes Beispiel für die Nutzung einer solchen sprechenden Schnittstelle ist die Anwendung des Mock-Frameworks Mockito:

when(uuidGenerator.getUUID()).thenReturn(15);

Auch ohne genauere Kenntnisse über Mockito kann der Programmierer aus diesem Beispiel herauslesen, dass wenn die Methode getUUID angefordert wird, im Rahmen des Mocks immer der Wert 15 zurückgegeben wird.

Die Zeile kann mit sprachlichen Mitteln einfach gelesen werden und verrät dem Nutzer etwas über die dahinterliegende Funktionalität. Das Ziel, die entsprechenden Schnittstellen einfach lesbar und benutzbar zu machen, wird sich dadurch erkauft, dass es meist aufwendiger ist, solche Schnittstellen zu designen und zu entwickeln.

Dies bedingt sich durch das vorher zu durchdenkende Design und einem Mehraufwand beim Schreiben des eigentlichen Quellcodes, unter anderem in Form zusätzlicher Methoden und anderen Objekten zur Abbildung des Fluent Interface.

Zur Implementierung von Fluent Interfaces werden unterschiedliche Techniken wie das Method Chaining genutzt. Daneben werden häufig Elemente wie statische Factory-Methoden und entsprechende Imports, sowie benannte Parameter genutzt.

Sprechende Schnittstellen ermöglichen es auch Personen einen Einblick in den Quellcode zu geben, welche nicht mit den technischen Details desselben vertraut sind. Auch bei der Abbildung von fachlicher Logik helfen Fluent Interfaces, z. B. über entsprechende Methodennamen, welche sich auf die Fachlichkeit der Anwendung beziehen.

Method Chaining

Eine der Techniken zur Erstellung von sprechenden Schnittstellen ist das Method Chaining, welches im Deutschen treffend mit Methodenverkettung übersetzt werden kann.

Methodenketten sind eine Technik, bei der mehrere Methoden aufeinanderfolgend aufgerufen werden, um ein Ergebnis zu erhalten. Beispielsweise könnte ein Entwickler mehrere Methoden aufrufen, um einen bestimmten Wert aus einem Array zu extrahieren oder einen Alternativwert bereitzustellen. Die Methodenketten ermöglichen es dem Entwickler, mehrere Aufgaben in einer Kette zu erledigen, anstatt sie auf getrennte Statements zu verteilen.

Das bedeutetet allerdings im Umkehrschluss nicht, dass die Verkettung von Methoden gleich einem Fluent Interface entspricht, sodass an dieser Stelle immer differenziert werden sollte.

Am Ende einer Methodenkette wird das benötigte Objekt zurückgegeben oder die gewünschte Aufgabe ausgeführt. Aussehen könnte eine solche Methodenkette, in diesem Fall am Beispiel der Stream-API, wie folgt:

User nathalie = Arrays.stream(users)
        .filter(user -> "Nathalie".equals(user.getForename()))
        .findFirst()
        .orElse(null);

Bei solchen Methodenketten gilt es zu berücksichtigen, dass bestimmte Methoden innerhalb der Kette im schlimmsten Fall null zurückgeben oder Exceptions auslösen. Je nach genutztem Interface müssen diese Fälle entsprechend beachtet werden.

Interessanterweise brechen Methodenketten mit einigen älteren Konventionen. So würden z. B. Setter in einem Builder-Pattern:

User.Builder.newBuilder()
               .name("Mustermann")
               .forename("Max")
               .username("maxmustermann")
               .build();

einen Wert zurückgeben, in diesem Beispiel das Builder-Objekt. Im Normalfall würde der Setter stattdessen keinen Rückgabeparameter aufweisen. Er wäre in einem gewöhnlichen Objekt wie folgt definiert:

public void setName(String name) {
    this.name = name;
}

Diese Konvention rührt vom Command-Query-Separation-Pattern, welches besagt, dass entweder Kommandos oder Queries definiert werden sollten. Abfragen als solche, dürfen keinerlei Auswirkungen am Zustand der Klasse haben, während bei Kommandos entsprechende Auswirkungen explizit erwünscht sind. Dies ist z. B. dann der Fall, wenn Daten geändert werden.

Method Nesting

Eine weitere Technik, welche für die Nutzung und das Design von Fluent Interfaces benutzt wird, ist das Method Nesting bzw. das Verschachteln von Methoden. Ein Beispiel hierfür liefert die Java-Bibliothek REST Assured, welche eine domänenspezifische Sprache zur Abfrage und Validierung von REST-Services darstellt:

when()
  .get("https://api.pi.delivery/v1/pi?start=0&numberOfDigits=100").
then()
  .statusCode(200)
  .body("content", startsWith("31415926535897932384"));

Neben der Verkettung von Methoden werden hier auch Methoden ineinander verschachtelt. In diesem Fall wird die startWith-Methode innerhalb der body-Methode geschachtelt, was dafür sorgt, dass beim Lesen ein besseres Verständnis entsteht, was im Quellcode passiert.

Die startWith-Methode stammt hierbei aus dem Hamcrest-Framework, welches viele solcher Methoden, unter anderem zur Nutzung in Unit-Tests, bereitstellt.

Statische Imports

Damit die Sprachelemente der Bibliothek im obigen Beispiel nicht immer voll referenziert werden müssen, werden statische Imports genutzt:

import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;

Damit kann eine statische Methode ohne ihren Klassennamen referenziert und genutzt werden. Ohne diesen statischen Import würde obiges Beispiel etwas umfangreicher aussehen:

RestAssured.when()
  .get("https://api.pi.delivery/v1/pi?start=0&numberOfDigits=100").
then()
  .statusCode(200)
  .body("content", Matchers.startsWith("31415926535897932384"));

Damit wird über den Mechanismus der statischen Importe sichergestellt, dass der Quelltext, im Rahmen der Philosophie der sprechenden Schnittstellen, möglichst lesbar bleibt.

Object Scoping

Vor allem in Programmiersprachen mit einem globalen Namensraum und echten Funktionen können Funktionen, welche einzelne Bestandteile einer domänenspezifischen Sprache darstellen, in diesem globalen Namensraum angelegt werden.

Allerdings ist dies in den meisten Fällen unerwünscht, sodass die Bestandteile der domänenspezifischen Sprache, wie im Beispiel REST Assured in entsprechende Objekte verpackt werden und damit den globalen Namensraum entlasten. Dieses Vorgehen trägt den Namen Object Scoping.

Anwendung

Doch wozu können solche Fluent Interfaces in der Praxis genutzt werden? Unterschiedlichste Szenarien werden immer wieder angesprochen, wenn es um die Nutzung dieser Technik geht.

Eine häufigere Anwendung ist das Builder-Pattern und die Nutzung in Form domänenspezifischer Sprachen kurz DSLs bzw. im englischen Original Domain Specific Languages.

Eine solche domänenspezifische Sprache ist eine Programmiersprache, welche für ein bestimmtes Feld, besagte Domäne, entwickelt wird. Häufig werden sie verwendet, um komplexe Aufgaben zu vereinfachen, indem eine auf die Domäne und die zu lösenden Probleme angepasste Syntax genutzt wird, welche meist große Schnittmengen mit der Fachlichkeit der Domäne beinhaltet.

Fluent Interfaces in der Java-Welt

Auch in der Java Class Library existieren APIs, welche als Fluent Interface angelegt sind. Ein prominentes Beispiel hierfür ist die Stream-API:

User aMustermann = Arrays.stream(users)
        .parallel()
        .filter(user -> "Mustermann".equals(user.getName()))
        .findAny()
        .orElse(null);

Über die Stream-API können unterschiedlichste Anforderungen abgebildet werden. In diesem Fall wird ein Array mit Objekten vom Typ User durchsucht und parallel ein Nutzer mit dem Nachnamen Mustermann gesucht. Dieses Objekt wird dann zurückgegeben. Wird kein solches Objekt gefunden, so wird stattdessen null zurückgegeben.

Auch in anderen Frameworks wie Mocking-Frameworks oder solchen Bibliotheken, welche domänenspezifische Sprachen abbilden, wird intensiv Gebrauch von Fluent Interfaces gemacht.

Frameworks, wie Spring, nutzen ebenfalls interne DSLs, um bestimmte Anforderungen und Möglichkeiten zur Konfiguration abzubilden.

Fluent Interfaces im Builder-Pattern

Eine weitere Anwendung für Fluent Interfaces im weiteren Sinne ist das sogenannte Builder-Pattern. Bei diesem existiert eine Klasse und ein dazugehöriger Builder, welcher dazu dient das Objekt zu konstruieren.

Hier wird ersichtlich, dass dies auf den ersten Blick mehr Aufwand bei der Implementation bedeutet. Allerdings müssen „Standardaufgaben“, wie das Erstellen eines Builders nicht unbedingt von Hand erledigt werden, da es für unterschiedlichste IDEs entsprechende Unterstützung in Form von Erweiterungen gibt. Für IntelliJ IDEA wäre ein Plugin für diese Aufgabe der InnerBuilder von Mathias Bogaert.

Ein Plugin für die einfache Erzeugung von Buildern in IntelliJ IDEA

Mithilfe dieser Plugins können Builder-Klassen schnell erstellt und bei Änderungen der eigentlichen Basisklasse angepasst werden, indem die Builder-Klasse über das Plugin neu generiert wird. Dies ermöglicht eine unkomplizierte Änderung von Klassen samt ihrer dazugehörigen Builder.

Manchmal wird beim Builder-Pattern infrage gestellt, ob es sich bei diesem wirklich um ein Fluent Interface handelt. Dabei wird die Unterscheidung getroffen, dass Fluent Interfaces sich mehr auf die Manipulation und Konfiguration von Objekten konzentrieren, während Builder den Fokus auf die Erzeugung von Objekten legen.

Es stellt sich allerdings die Frage, inwiefern diese Gedanken akademischer Natur, in der Praxis relevant sind, da auch Builder sich aus Sicht des Lesers des Quellcodes gut als Fluent Interfaces erschließen lassen.

Builder-Pattern im Beispiel

Wie könnte ein solches Builder-Pattern nun an einem einfachen Beispiel aussehen? Gegeben sei folgende Klasse:

public class User {

    private String name;

    private String forename;

    private String username;

    public User() {
    }
}

Die Klasse mit dem Namen User enthält drei Felder in welchen der Name, Vorname und der Nutzername des Nutzers gespeichert werden. Um die Felder der Klasse zu befüllen, existieren unterschiedliche Möglichkeiten.

So könnte ein entsprechender Konstruktor definiert werden, welcher diese Felder setzt:

public User(String name, String forename, String username) {
    this.name = name;
    this.forename = forename;
    this.username = username;
}

Dieser könnte nun aufgerufen werden, um eine Instanz der Klasse zu erstellen und die Felder zu füllen:

User max = new User("Mustermann", "Max", "maxmustermann");

Soll jedoch ein Wert nicht gesetzt werden, kann dieser auf null gesetzt werden. Allerdings kann es hier auch den Fall geben, dass mit NotNull-Annotationen und einer entsprechenden Validation gearbeitet wird:

public User(@NotNull String name, @NotNull String forename, @NotNull String username)

Durch die Annotation soll verhindert werden, dass die entsprechenden Felder mit dem Wert null initialisiert werden können. In einem solchen Fall ist für die entsprechenden Felder auch die Anwendung des Builder-Patterns nur schwer vorstellbar, z. B. über das Setzen der Werte in der newBuilder-Methode.

Sind solche Einschränkungen nicht vorhanden, könnte alternativ mit unterschiedlichen Konstruktoren gearbeitet werden, in welchen jeweils nur einige der Felder gesetzt werden können.

Spätestens bei komplexeren Objekten wird auffallen, dass diese Methode eher ungeeignet ist. Der klassische Weg ist es hier entsprechende Getter und Setter zum Abrufen und Setzen der Eigenschaften bereitzustellen:

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getForename() {
    return forename;
}

public void setForename(String forename) {
    this.forename = forename;
}

public String getUsername() {
    return username;
}

public void setUsername(String username) {
    this.username = username;
}

Zwar können Getter und Setter auch über Annotationen, z. B. mithilfe der Bibliothek Lombok, vor dem Compile-Vorgang, generiert werden, allerdings hält der Autor nicht sonderlich viel von dieser Art von „Präprozessor-Magie“.

Hierbei werden unnötige Abhängigkeiten für doch recht simple Aufgaben, an das Projekt angehangen, welche wiederum bestimmte Funktionsweisen vor dem Entwickler verstecken. Vor allem, wenn der Entwickler nicht mit dem Projekt vertraut ist, kann dies das Verständnis erschweren.

Unter Nutzung der Setter kann ein Objekt nun feingranular mit den gewünschten Werten befüllt werden:

User user = new User();

user.setName("Mustermann");
user.setForename("Max");
user.setUsername("maxmustermann");

Soll z. B. der Vorname nicht gesetzt werden, so kann die entsprechende Zeile einfach weggelassen werden. Diese Nutzung bzw. Schreibweise wird manchmal unter dem Namen Method Sequencing zusammengefasst.

An dieser Stelle könnte stattdessen ein Builder genutzt werden. Bei diesem würde das Ganze wie folgt aussehen:

User user = User.Builder.newBuilder()
        .name("Mustermann")
        .forename("Max")
        .username("maxmustermann")
        .build();

Bei dieser Schreibweise wird der Builder genutzt, um das Objekt zu erstellen und mit seinen Werten zu befüllen. Der Builder liefert dazu die benötigen Methoden:

public static final class Builder {
    private String name;
    private String forename;
    private String username;

    private Builder() {
    }

    public static Builder newBuilder() {
        return new Builder();
    }

    public Builder name(String name) {
        this.name = name;
        return this;
    }

    public Builder forename(String forename) {
        this.forename = forename;
        return this;
    }

    public Builder username(String username) {
        this.username = username;
        return this;
    }

    public User build() {
        return new User(this);
    }
}

In vielen modernen Implementationen des Pattern wird meist auf das Präfix set für die Setter verzichtet und stattdessen nur der Name des Feldes als Methode definiert. Alternativ wird häufig auch das Präfix with genutzt.

Beim Quelltext wird ersichtlich, dass jede Methode, bis auf die build-Methode, eine Instanz des Builders zurückgibt und damit die Verkettung der unterschiedlichen Methoden erlaubt.

Fluent Interfaces zur Definition einer DSL nutzen

Neben dem Entwicklungsmuster des Builders können mithilfe von Fluent Interfaces domänenspezifische Sprachen (DSLs) erstellt werden.

Bei solchen Sprachen handelt es sich um speziell für ein bestimmtes Anwendungsgebiet entwickelte Programmiersprachen. Sie sind oft einfacher und leichter zu verstehen als allgemeine Programmiersprachen und ermöglichen es Entwicklern bzw. den Anwendern der Sprache, effizienter und präziser zu programmieren.

DSLs werden häufig in bestimmten Bereichen wie der Finanzbranche, der Medizin, der Luftfahrtindustrie, der Spieleentwicklung und der Datenanalyse eingesetzt. Sie können dazu beitragen, Prozesse zu automatisieren und zu vereinfachen und ermöglichen Entwicklern, komplexe Aufgaben in kürzerer Zeit zu erledigen.

Zu den bekanntesten domänenspezifischen Sprachen gehört SQL und auch reguläre Ausdrücke können als DSL gesehen werden. Grundsätzlich werden domänenspezifischen Sprachen in externe und interne Sprachen unterteilt.

Bei den internen DSLs wird eine Wirtssprache, in diesem Beispiel Java, genutzt, um die DSL abzubilden. Externe DSLs hingegen stehen für sich allein und nutzen keinerlei Wirtssprache. Deshalb sind sie auf eigens dafür entwickelte Compiler oder Interpreter angewiesen.

Im folgenden Beispiel soll eine DSL für HTML entwickelt und anhand dieser sollen einige Konzepte der sprechenden Schnittstellen in Zusammenhang gebracht werden. Die HTML-DSL soll dazu genutzt werden, HTML-Dokumente zu bauen. Ein Aufruf dieser DSL könnte wie folgt aussehen:

String html = new Html()
        .head()
          .meta("UTF-8")
          .meta("keywords", "fluent, interface")
          .title("Fluent interfaces")
          .finalise()
        .body()
          .text("Fluent interfaces")
          .br()
          .finalise()
        .generate();

Während bei einem einfachen Builder immer der Builder als solcher zurückgegeben wird, wird in diesem Fall nicht immer das Hauptobjekt, die Klasse Html, zurückgegeben. Stattdessen werden teilweise sogenannte Intermediate-Objekte zurückgegeben. Diese haben außerhalb der DSL keinerlei sinnvolle Funktionalität, sondern dienen dazu nur die Methoden anzubieten, welche im Kontext von HTML erlaubt sind.

Über Intermediate-Objekte lassen sich somit auch bestimmten Reihenfolgen erzwingen. Damit kann der Compiler zumindest zur partiellen Überprüfung der Anweisungen benutzt werden und dem Anwender bzw. Entwickler werden nur die Funktionalitäten zur Verfügung gestellt, welche im entsprechenden Kontext sinnvoll sind.

Über die Intermediate-Objekte werden die entsprechenden Methoden zur Verfügung gestellt

Unterstützt wird der Entwickler daneben durch die Autovervollständigung der IDE, welche die Methoden des jeweiligen Intermediate-Objektes darstellen kann. Anschließend dient die Methode finalise dazu, wieder eine Ebene höher in der Hierarchie der Intermediate-Objekte zu wandern.

In der Theorie könnten die entsprechende Verschachtelung beliebig komplex gestaltet werden. So können div-Blöcke als Elemente genutzt werden und innerhalb des Intermediate-Objektes für den div-Block stehen dann ausschließlich solche Elemente, welche im Rahmen eines div-Blockes genutzt werden können.

Bei der Nutzung einer solchen domänenspezifischen Sprache ist es wichtig, dass der jeweilige Aufruf auch sinnvoll beendet werden muss. So kann es bei falscher Nutzung durchaus passieren, dass der Entwickler, wenn er entsprechende Aufrufe vergisst, ein Intermediate-Objekt als Rückgabe am Ende erhält, mit welchem er nicht viel anfangen kann. Dieses Problem wird auch als Finishing-Problem bezeichnet.

Beim Design einer DSL muss immer sichergestellt werden, dass es einen Aufruf in den jeweiligen Intermediate-Objekten gibt, welcher dafür sorgt am Ende ein sinnvolles Ergebnis zu erhalten bzw. wieder zum eigentlichen Objekt zurückführt.

Automatische Generation von sprechenden Schnittstellen

Viele domänenspezifische Sprachen werden von Hand geschrieben, allerdings existieren durchaus Ansätze solche Sprachen auch über eine entsprechende definierte Grammatik zu generieren.

Auch Codegeneratoren wie z. B. für GraphQL-Schnittstellen erzeugen unter Umständen Fluent Interfaces, welche dann genutzt werden können:

return new ProductResponseProjection()
        .categoryId()
        .categoryName()
        .issuingCountry();

In diesem Fall wird aus dem GraphQL-Schema eine entsprechende API plus das dazugehörige Modell generiert, welches sich dann nach Außen hin als Builder– bzw. Fluent Interface darstellt.

Ob und wieweit die Generierung von sprechenden Schnittstellen automatisiert werden kann, hängt immer sehr stark vom jeweiligen Anwendungsfall ab.

Fazit

Fluent Interfaces sind ein Begriff, der nun schon eine Weile durch die Welt geistert und wahrscheinlich finden sich in den Köpfen unterschiedliche Vorstellung davon.

Teilweise ist es schwierig, eine harte Definition von sprechenden Schnittstellen zu finden, wie der StringBuilder unter Java zeigt:

String abc = new StringBuilder()
        .append("ABC")
        .append("DEF")
        .append("GHJ")
        .toString();

Die append-Methode stellt hier eine Art Builder-Pattern in Form einer sprechenden Schnittstelle zur Verfügung und kann damit im Kleinen als solche gesehen werden. Die Bandbreite von Fluent Interfaces im Kleinen, wie dem Builder-Pattern, bis zu ausgewachsenen domänenspezifischen Sprachen mit eigenen Grammatiken ist groß.

Alles in allem spielen sprechende Schnittstellen vorwiegend bei komplexen Objekten und entsprechenden Use Cases ihre Stärken aus. Sie sorgen für mehr Verständnis und nutzen die Möglichkeiten des Compilers und der IDE zur Unterstützung aus.

Trotz der Vorteile, welche solche sprechenden Schnittstellen bieten, sollte vor der Implementation immer genau überlegt werden, ob für den jeweiligen Anwendungszweck wirklich ein solche benötigt wird. Hier sollte die erhöhte Komplexität in der Implementation und Pflege mit der Notwendigkeit abgewogen werden.

Der Quellcode der einzelnen vorgestellten sprechenden Schnittstellen kann über GitHub eingesehen und ausprobiert werden.

Dieser Artikel erschien ursprünglich auf Golem.de und ist hier in einer alternativen Variante zu finden.

Scrollrichtung für die Magic Mouse einstellen

Vor ein paar Tagen schrieb ich wie sich die Scrollrichtung unter macOS unabhängig einstellen lässt. Während dies mit klassischen Mäusen problemlos funktioniert, sieht es bei der Magic Mouse von Apple leider anders aus. Dort ist die Scrollrichtung identisch mit der für das Trackpad.

Die Einstellungen von Scroll Reverser

In den Augen des Autors von UnnaturalScrollWheels ist dies allerdings kein Fehler, mit einer durchaus nachvollziehbaren Argumentation. Allerdings gibt es mit Scroll Reverser eine Alternative, welche ebenfalls über Homebrew installiert werden kann:

brew install scroll-reverser

Auch mit Scroll Reverser kann die Scrollrichtung von Maus und Trackpad angepasst werden. Im Gegensatz zu UnnaturalScrollWheels, funktioniert dies auch in Verbindung mit der Magic Mouse.

Der Quelltext der App ist auf GitHub zu finden und unter der Apache License lizenziert. Damit ist das Tool freie Software.