1 points par GN⁺ 2026-02-02 | 1 commentaires | Partager sur WhatsApp
  • Exemple de l’ajout d’une option --dry-run lors du développement d’une application de génération de rapports afin de pouvoir simuler le résultat de l’exécution
  • Cette option affiche quelles opérations seraient effectuées sans appliquer de modifications réelles, ce qui permet des tests sûrs et un retour rapide
  • Le développeur peut ainsi vérifier immédiatement la configuration, l’accessibilité et l’état du système, et l’utiliser comme outil de vérification au quotidien
  • Comme inconvénient, une légère augmentation de la complexité est mentionnée, car il faut vérifier le flag dryRun dans le code
  • Dans les applications impératives, la fonctionnalité --dry-run est très utile, et plus elle est introduite tôt dans le projet, plus l’efficacité du développement augmente

Contexte

  • La nouvelle application de génération de rapports en cours de développement génère chaque jour ouvré des rapports, les compresse, les envoie vers un serveur sftp, vérifie les réponses d’erreur et envoie des e-mails de notification
    • Les fichiers générés et les fichiers de retour produits à chaque étape sont déplacés vers des répertoires différents selon l’étape
  • Au début du développement, en repensant à Subversion et à l’option --dry-run de plusieurs commandes Linux, la même fonctionnalité a été ajoutée
    • Cette option affiche ce qui se passerait à l’exécution sans effectuer de changement réel
  • Lors d’une exécution avec --dry-run, les rapports qui seraient générés et ceux qui seraient exclus, les fichiers qui seraient compressés et déplacés, ainsi que les fichiers concernés par l’upload et le téléchargement sftp sont affichés étape par étape

Utilisation et avantages

  • Une fonctionnalité suffisamment utile pour être utilisée tous les jours pendant le développement et les tests
  • Utilisée pour vérifier l’état avant exécution, elle permet de contrôler immédiatement la configuration, l’accessibilité et l’état du système
    • Comme aucun changement réel n’est effectué, elle peut être exécutée en toute sécurité
  • En modifiant la date du fichier d’état d’un rapport, il est possible de vérifier immédiatement si ce rapport sera généré
    • La génération réelle du rapport prend du temps, mais le dry-run fournit un retour rapide
  • Même lors des tests de l’ensemble du système, il offre une boucle de validation rapide

Inconvénients

  • Il faut vérifier de façon répétée le flag dryRun dans le code, ce qui entraîne une légère pollution du code
    • À chaque étape principale, le flag est contrôlé pour n’afficher que des logs au lieu d’exécuter réellement l’action
  • Cependant, cette vérification n’est pas profonde et aucun traitement particulier n’est nécessaire à l’intérieur de la logique de génération de rapports
    • La vérification n’est faite qu’au niveau supérieur, là où l’exécution effective est décidée

Conclusion

  • Les applications exécutées de manière impérative et qui produisent un résultat se prêtent bien à une option --dry-run
    • En revanche, elle ne convient pas aux applications réactives qui attendent des messages
  • Le fait de l’avoir ajoutée dès le début du projet a été d’une grande aide pour améliorer l’efficacité du développement
  • Ce n’est pas une fonctionnalité nécessaire dans tous les cas, mais elle est considérée comme un outil très utile lorsqu’elle est appropriée

1 commentaires

 
GN⁺ 2026-02-02
Avis Hacker News
  • Lorsqu’on interagit avec des systèmes à état, il peut aussi y avoir des conditions de concurrence (race conditions) avec --dry-run
    L’outil montre « ce qu’il va faire » à l’instant T, mais au moment de l’exécution réelle, la situation peut avoir changé
    C’est pourquoi je préfère l’approche du mode "plan" de Terraform. Ce mode prépare un plan exécutable, puis peut s’interrompre ou revenir en arrière si les hypothèses faites au moment du plan ont changé
    Cela évite aussi de parsemer le code de if dry_run: et permet de simplifier en séparant planification et exécution sous une forme execute(plan())

    • Un ancien incident DNS chez AWS provenait d’une condition de concurrence similaire
      Un problème de timing entre DNS Planner et Enactor a conduit un ancien plan à écraser le plus récent
      Le sujet avait aussi été abordé dans un précédent fil HN
    • Au final, cela revient à implémenter un compilateur (spécification → plan) et une machine virtuelle (plan → exécution)
    • C’est idéal pour des outils d’infrastructure comme Terraform ou Ansible, mais cela peut introduire une complexité excessive dans un simple outil de reporting
      Car créer un mode plan suppose un langage dédié au domaine ou des structures de données adaptées
    • Je développe moi aussi un script qui modifie des fichiers sensibles, et j’applique cette approche
      (1) capturer l’état du système de fichiers et enregistrer un plan → (2) vérifier que l’état n’a pas changé, puis exécuter et journaliser → (3) comparer à l’état précédent pour valider l’absence de perte de données
      J’utilise ces trois étapes comme scripts séparés ou via des flags distincts
    • Je me demande alors comment on pourrait appliquer un tel mode plan à la commande rm
  • Quand un outil n’a pas de --dry-run, il m’arrive d’en bricoler un moi-même
    Par exemple, avant d’exécuter une commande sed complexe, j’utilise diff pour comparer à l’avance les modifications
    On peut voir les différences avec quelque chose comme diff -u <(echo "hello") <(echo "hello" | sed "s/hello/hi/g")
    J’ai résumé tout ça dans mon blog

  • J’aime le pattern --dry-run, mais le code du chemin dry-run doit se comporter comme le chemin réel
    Si on se contente d’afficher « ce qui va se passer » en sautant la vraie logique, on risque de laisser passer des bugs au moment de l’exécution réelle
    Il faut que le déroulement soit identique jusqu’au point juste avant les écritures en base de données ou les appels d’API

    • Mais pour certains, cela revient à confondre tests d’intégration et dry-run
      Un dry-run sert à montrer « ce qui se passerait », tandis que les vrais tests relèvent d’un autre domaine
  • À l’inverse, je préfère avoir un flag --commit ou --execute, et faire de l’exécution par défaut un mode lecture seule (dry)
    Cela réduit le risque de provoquer de vraies modifications par erreur

    • J’utilise cette approche depuis 8 ans, et elle s’est révélée sûre puisque les changements ne se produisent que si --commit est explicitement indiqué
      En revanche, j’ai souvent vu des incidents causés par l’oubli de --dry-run
    • Mon outil de déduplication de répertoires suit aussi ce modèle
      Par défaut, il ne fait que comparer, et il faut --execute pour réellement remplacer par des hard links
    • Parmi les outils que j’ai utilisés, certains demandaient autrefois de saisir une phrase précise avant l’exécution réelle
      Ce type de confirmation est efficace pour réduire les erreurs
    • Personnellement, j’aime aussi des flags comme --wet-run. Selon le contexte, un flag au sens inverse peut parfois être plus intuitif
    • Dans un script récent, le mode par défaut est la lecture seule, et pour effectuer une suppression réelle il faut saisir manuellement DELETE-ACCOUNT
      Jusqu’à présent, je n’ai jamais supprimé un compte par erreur une seule fois
  • Pour éviter de polluer le code, il faut séparer la persistance comme une stratégie injectable
    Mettre des if dry_run: partout n’est pas une bonne idée
    Il est même plus sûr de rendre l’exécution de production explicite avec --wet-run

    • Il est bon de modéliser explicitement le comportement de l’application et de le traiter de manière centralisée
      Ainsi, la décision dry-run ou non ne se prend qu’en un seul endroit — dans un style « functional core, imperative shell »
    • Mais devoir taper à chaque fois quelque chose comme rm --wet-run tempfile.tmp est pénible
      Je préférerais que l’exécution réelle reste le comportement par défaut, avec à la place une option --undo pour annuler la dernière action
    • Je n’aime pas le nom --wet-run, mais j’ai déjà utilisé une approche où le mode par défaut est dry-run et où il faut préciser --no-dry-run pour permettre les modifications
      Pour un service, l’idéal serait de sélectionner automatiquement le mode de sécurité selon l’environnement d’exécution (dev/prod)
    • Dans ce genre de cas, l’usage de design patterns permet de garder une structure propre
  • L’article disait : « j’ai ajouté --dry-run au début et cela s’est révélé étonnamment utile », mais
    en réalité, ce type de flag est souvent proposé automatiquement par des agents de code IA (par ex. Claude)
    Si beaucoup d’outils CLI présentent aujourd’hui des patterns similaires, cela vient peut-être de cette convergence du code pilotée par les agents

    • Mais comme l’auteur mentionne explicitement s’être inspiré du --dry-run de Subversion, cela reste une explication tout à fait convaincante
  • Dans mes utilitaires CLI, j’ajoute souvent un flag --really afin que le comportement par défaut reste en lecture seule
    L’idée est d’exiger une confirmation délibérée pour éviter les erreurs

    • J’ai aussi déjà vu une commande avec un flag --i-meant-that
      C’était une commande de suppression de machine distante, et par défaut elle attendait 10 secondes pour laisser le temps d’annuler
      Heureusement, ce flag n’a jamais été utilisé à tort
  • L’un des aspects sympas de PowerShell, c’est qu’en ajoutant simplement [CmdletBinding(SupportsShouldProcess)],
    on obtient automatiquement la fonctionnalité de dry-run -WhatIf. C’est une fonction très pratique

    • En plus, cela active aussi -Confirm, et permet d’interagir avec le seuil de confirmation de l’utilisateur via la fonction ShouldProcess. C’est vraiment une belle conception
  • Dans la CLI interne dont je m’occupe, je place if not dry_run: dans la partie qui appelle l’API REST
    Ainsi, au lieu de faire l’appel réel, on conserve un log de commande CURL pour voir quelles requêtes seraient envoyées
    Mais quand les interactions entre API deviennent complexes, la simulation devient difficile et bien plus compliquée qu’un simple if not dry_run:

    • Structurer le code pour que l’action réelle ne se produise qu’en un seul endroit permet d’éviter cette pollution
      Je maintiens moi aussi beaucoup de CLI pour des pipelines d’automatisation, et j’applique ce pattern à presque tous mes outils
    • Mais certains estiment qu’un usage excessif de REST dans des outils console est inefficace
      Selon eux, il vaut mieux d’abord bien concevoir les outils locaux
  • Si le flag --dry-run est dispersé dans tout le code, il vaut mieux appliquer le pattern de machine à états pour séparer clairement chaque étape