Über die Vorteile der Option `--dry-run`
(henrikwarne.com)- Ein Beispiel aus der Entwicklung einer Anwendung zur Berichtserstellung, bei der eine
--dry-run-Option hinzugefügt wurde, um das Ausführungsergebnis zu simulieren - Diese Option gibt aus, welche Aktionen ausgeführt würden, ohne tatsächliche Änderungen vorzunehmen, und ermöglicht so sichere Tests und schnelles Feedback
- Entwickler können damit Konfiguration, Zugänglichkeit und Systemzustand sofort prüfen und sie als alltägliches Verifizierungswerkzeug nutzen
- Als Nachteil wird eine leicht erhöhte Komplexität genannt, da im Code das Flag
dryRungeprüft werden muss - Bei imperativen Anwendungen ist die
--dry-run-Funktion sehr nützlich; je früher sie im Projekt eingeführt wird, desto höher ist die Entwicklungseffizienz
Hintergrund
- Die neu entwickelte Anwendung zur Berichtserstellung erzeugt an jedem Werktag Berichte, komprimiert sie, lädt sie auf einen sftp-Server hoch, prüft Fehlerantworten und verschickt Benachrichtigungs-E-Mails
- In jedem Schritt erzeugte Dateien und Feedback-Dateien werden in unterschiedliche Verzeichnisse pro Phase verschoben
- Zu Beginn der Entwicklung erinnerte man sich an Subversion und die
--dry-run-Option vieler Linux-Befehle und fügte dieselbe Funktion hinzu- Diese Option gibt aus, was bei der Ausführung passieren würde, ohne echte Änderungen vorzunehmen
- Bei einer Ausführung mit
--dry-runwerden die zu erzeugenden und auszuschließenden Berichte, die zu komprimierenden und zu verschiebenden Dateien sowie die per sftp hoch- und herunterzuladenden Dateien schrittweise ausgegeben
Nutzung und Vorteile
- Eine so nützliche Funktion, dass sie im Entwicklungs- und Testprozess täglich verwendet wird
- Wenn sie zur Zustandsprüfung vor der Ausführung verwendet wird, lassen sich Konfiguration, Zugänglichkeit und Systemzustand sofort überprüfen
- Da keine tatsächlichen Änderungen vorgenommen werden, kann sie sicher ausgeführt werden
- Wenn das Datum der Statusdatei eines Berichts geändert wird, lässt sich sofort prüfen, ob dieser Bericht erzeugt werden würde
- Die eigentliche Berichtserstellung braucht Zeit, aber
--dry-runliefert schnelles Feedback
- Die eigentliche Berichtserstellung braucht Zeit, aber
- Auch beim Testen des Gesamtsystems bietet sie eine schnelle Validierungsschleife
Nachteile
- Da im Code das Flag
dryRunwiederholt geprüft werden muss, entsteht eine leichte Verunreinigung des Codes- In jedem Hauptschritt wird das Flag geprüft, sodass statt der echten Ausführung nur Logs ausgegeben werden
- Diese Prüfungen reichen jedoch nicht tief hinein, und innerhalb der Logik zur Berichtserstellung ist keine gesonderte Behandlung nötig
- Geprüft wird nur auf der übergeordneten Ebene, die über die Ausführung entscheidet
Fazit
- Anwendungen, die imperativ ausgeführt werden und Ergebnisse erzeugen, passen gut zu einer
--dry-run-Option- Für reaktive Anwendungen, die auf Nachrichten warten, ist sie dagegen nicht geeignet
- Dass sie früh im Projekt hinzugefügt wurde, half erheblich dabei, die Entwicklungseffizienz zu steigern
- Sie ist nicht in jeder Situation nötig, wird aber im passenden Fall als sehr nützliches Werkzeug bewertet
1 Kommentare
Hacker-News-Kommentare
Bei der Interaktion mit zustandsbehafteten Systemen kann es auch bei
--dry-runzu Race Conditions kommenDas Tool zeigt zwar, „was es tun würde“, aber zum Zeitpunkt der tatsächlichen Ausführung kann sich die Lage bereits geändert haben
Deshalb bevorzuge ich den Ansatz des „plan“-Modus von Terraform. Dieser Modus erzeugt einen ausführbaren Plan, und wenn sich die Annahmen vom Planungszeitpunkt ändern, kann man abbrechen oder ein Rollback ausführen
Außerdem muss man nicht überall im Code
if dry_run:einstreuen und kann Planung und Ausführung trennen und zu etwas wieexecute(plan())vereinfachenWegen eines Timing-Problems zwischen DNS Planner und Enactor hat ein veralteter Plan den aktuellen Plan überschrieben
Das wurde auch im früheren HN-Thread behandelt
Denn um einen Plan-Modus zu bauen, braucht man eine domänenspezifische Sprache oder passende Datenstrukturen
(1) Zustand des Dateisystems erfassen und den Plan speichern → (2) prüfen, ob sich der Zustand nicht verändert hat, dann ausführen und protokollieren → (3) mit dem vorherigen Zustand vergleichen und auf Datenverlust prüfen
Ich nutze diese drei Schritte getrennt als eigene Skripte oder Flags
rmanwenden könnteWenn ein Tool kein
--dry-runhat, baue ich mir manchmal selbst etwas VergleichbaresBevor ich zum Beispiel einen komplexen
sed-Befehl ausführe, vergleiche ich mitdiffvorab die ÄnderungenMit
diff -u <(echo "hello") <(echo "hello" | sed "s/hello/hi/g")kann man sich die Unterschiede ansehenMehr dazu habe ich in meinem Blog gesammelt
Ich mag das Muster
--dry-run, aber der Codepfad für den Dry Run muss sich genauso verhalten wie der echte PfadWenn man nur ausgibt, „was passieren würde“, und die eigentliche Logik überspringt, kann man Bugs in der echten Ausführung übersehen
Bis kurz vor Datenbank-Schreibvorgängen oder API-Aufrufen sollte alles identisch laufen
Ein Dry Run zeigt, „was passieren wird“, während echtes Testen ein eigener Bereich ist
Ich bevorzuge eher
--commitoder--execute, während die Standardausführung read-only (dry) bleibtSo sinkt die Wahrscheinlichkeit, versehentlich echte Änderungen auszulösen
--commitpassierenDagegen gab es viele Unfälle, weil jemand vergessen hat,
--dry-runanzugebenStandardmäßig vergleicht es nur, und erst mit
--executewerden tatsächlich Hardlinks eingesetztSolche Bestätigungsschritte helfen effektiv gegen Fehler
--wet-run. Je nach Situation ist ein Flag mit umgekehrter Bedeutung manchmal intuitiverDELETE-ACCOUNTdirekt eingebenBis heute habe ich noch nie versehentlich ein Konto gelöscht
Um Code-Verschmutzung zu vermeiden, sollte man Persistenz als injizierbare Strategie auslagern
Es ist keine gute Idee, überall
if dry_run:zu verteilenSicherer ist es eher, die Produktivausführung explizit als
--wet-runzu markierenDann muss nur an einer Stelle entschieden werden, ob es ein Dry Run ist — im Stil von „functional core, imperative shell“
rm --wet-run tempfile.tmpeinzugebenBesser wäre echte Ausführung als Standard und stattdessen eine Option
--undo, um den letzten Vorgang rückgängig zu machen--wet-rungefällt mir zwar nicht, aber ich habe auch schon Systeme genutzt, bei denen standardmäßigdry-runaktiv war und Änderungen nur mit explizitem--no-dry-runmöglich warenBei Services wäre es ideal, je nach Laufzeitumgebung (dev/prod) automatisch einen sicheren Modus zu wählen
Im Artikel hieß es, man habe früh
--dry-runergänzt und sei überrascht gewesen, wie nützlich das war,tatsächlich werden solche Flags aber oft von AI-Coding-Agenten (z. B. Claude) automatisch vorgeschlagen
Dass viele CLI-Tools heute ähnliche Muster haben, könnte auch an dieser agentengetriebenen Konvergenz im Code liegen
--dry-runkam, daher ist das als Begründung durchaus überzeugendIch ergänze bei CLI-Utilities oft ein Flag
--really, sodass standardmäßig nur read-only gearbeitet wirdDamit verlange ich eine bewusste Bestätigung, um Fehler zu vermeiden
--i-meant-thatDas war ein Kommando zum Löschen entfernter Maschinen, das standardmäßig 10 Sekunden wartete und Gelegenheit zum Abbrechen gab
Zum Glück wurde dieses Flag nie falsch verwendet
Eines der großartigen Dinge an PowerShell ist, dass man mit einer einzigen Zeile
[CmdletBinding(SupportsShouldProcess)]automatisch die Dry-Run-Funktion
-WhatIfbekommt. Das ist eine sehr praktische Funktion-Confirmaktiviert, und über die FunktionShouldProcesskann man mit der Bestätigungsschwelle für den Benutzer interagieren. Wirklich ein tolles DesignIn einer internen CLI, die ich betreue, setze ich
if not dry_run:im Bereich der REST-API-Aufrufe einSo kann ich statt echter Aufrufe CURL-Befehle protokollieren, damit sichtbar ist, welche Requests rausgehen würden
Wenn die Verknüpfungen zwischen APIs komplexer werden, wird die Simulation aber schwierig und deutlich komplizierter als ein simples
if not dry_run:Ich betreue auch viele CLIs für Automatisierungs-Pipelines und verwende dieses Muster in fast allen Tools
Wichtiger sei es, zuerst gute lokale Tools zu bauen
Wenn das Flag
--dry-runim ganzen Code verstreut ist, sollte man besser das State-Machine-Pattern anwenden, um die einzelnen Schritte klar zu trennen