© Enkel/Shutterstock.com
Wie relevant sind Software-Crafting-Techniken heute noch?

Cruft oder Craft?


Wir schreiben das Jahr 2020. Wenn die werten Lesenden diesen Artikel zu Gesicht bekommen, wird es 2021 sein – mehr als 25 Jahre, nachdem Kent Beck Extreme Programming entwickelt und damit ein Umdenken hinsichtlich unserer Art, Software zu entwickeln, angestoßen hat. Zeit, sich zu fragen, ob die Programmierpraktiken, die mit agiler Softwareentwicklung verbunden werden, den Anforderungen des 21. Jahrhunderts noch gewachsen sind.

Seit den Anfängen der agilen Bewegung hat sich einiges getan: Java war damals gerade ein Jahr alt und der entwickelte Code lief auf riesigen Servern, die von Ops-Abteilungen gehegt und gepflegt wurden. Heute sieht Java viel funktionaler aus und wir deployen mit einem git push vollautomatisiert in PaaS-Infrastruktur oder entwickeln Serverless Functions in der Cloud. Viele von uns entwickeln in neueren Programmiersprachen wie Kotlin. Sind die älteren Praktiken hinsichtlich der vielen modernen Tools in die Jahre gekommen oder braucht man sie heute mehr denn je?

Testgetriebene Entwicklung (TDD)

Die drei von Robert Martin formulierten Regeln [1] zur testgetriebenen Entwicklung sorgen dafür, dass jeder neu geschriebene Code von einem Test abgedeckt ist:

  1. Schreibe keinen Code ohne einen fehlschlagenden Test.

  2. Schreibe gerade so viel Testcode, dass ein Test fehlschlägt (Compilerfehler zählen als Fehlschlag).

  3. Schreibe nur so viel Produktivcode, dass der rote Test gerade grün wird.

Parallel zum Code wird dadurch ein Sicherheitsnetz aus Tests entwickelt, das sofort Alarm schlägt, wenn eine Änderung ungewollt bestehende Funktionalität beeinflusst. Dieses Sicherheitsnetz ermöglicht Refactoring ohne großes Risiko.

Testgetriebene Entwicklung ist das Äquivalent zur doppelten Buchführung. Jede Änderung am Code wird doppelt vorgehalten, um sich gegen Fehler beim Programmieren abzusichern. Parallel dazu dienen die Tests als ausführbare Dokumentation des Produktivcodes. Als neues Mitglied im Team freut man sich über eine solche Dokumentation mehr als über längst veraltete Prosa von vor zwei Versionen. Mit Tests und ihren Eingabewerten kann man experimentieren, um ein Gefühl für den zu bearbeitenden Code zu bekommen. Hinter TDD stecken mehrere Einsichten:

  • Entwickler machen Fehler

  • Software ist zu komplex, als dass man mit einem Blick sagen könnte, ob sie funktioniert oder nicht

  • Korrektheit lässt sich nur experimentell (durch Tests) nachweisen. Ein Beweis wäre zwar theoretisch möglich, ist aber meist nicht praktikabel

In den letzten Jahren hat die Komplexität der Softwareentwicklung eher noch zu- als abgenommen. Allein im Java-Ökosystem ist die Zahl der Bibliotheken rasant gewachsen. Maven Central allein stellt mehr als 350 000 Artefakte bereit, wovon jedes nochmal in mehreren Versionen vorliegt. Dazu kommt eine Zunahme bei der Komplexität der Infrastruktur. Code in der Cloud muss mit Code auf traditioneller Infrastruktur interagieren, denn die wenigsten bestehenden Projekte haben einen sauberen Absprung in die Cloud geschafft. Dasselbe Modul muss oft auf traditioneller Infrastruktur und gleichzeitig in der Cloud lauffähig sein. Ohne sauberes Design und saubere Architektur ist das langfristig nicht möglich.

TDD hilft dabei, den Produktionscode vom Rest des Systems zu entkoppeln, damit er testbar ist. Hat man die initiale Frustration beim Lernen von TDD überwunden, beginnt man, die Schmerzen beim Schreiben von gekoppeltem Code als Zeichen für Designprobleme zu erkennen. Statt sie als Ärgernis zu ignorieren und die Tests wie gehabt zu schreiben, fängt man an, die Produktionsklassen so zu entwickeln, dass das Testen leichter wird – man entkoppelt sie von ihrer Umgebung. Beispielsweise werden Konfigurationsobjekte in der gleichen Weise wie Stores und Gateways per Dependency Injection über den Konstruktor an das zu konfigurierende Objekt übergeben, statt die Konfiguration direkt in der Klasse aus einer Datei einzulesen. Damit hat man die Grundlage dafür geschaffen, dass die Software nicht nur auf traditionellen Umgebungen läuft, wo die Konfigurationsobjekte aus Dateien befüllt werden, sondern auch in der Cloud, wo nach Twelve-Factor-App-Prinzip [2] die Konfiguration aus der Umgebung kommen soll. In der Cloud werden die Konfigurationsobjekte dann aus Umgebungsvariablen befüllt. Für die konfigurierte Klasse ist das transparent. Solange sie ein Konfigurationsobjekt bekommt, funktioniert sie. Für die Tests ist es ebenso leicht, die Klasse zu konfigurieren. Sie erzeugen In-memory-Konfigurationsobjekte und übergeben sie an den Konstruktor. An dieser Stelle...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang