- レポート生成アプリケーションの開発過程で
--dry-run オプションを追加し、実行結果をシミュレーションできるようにした事例
- このオプションは実際の変更を行わずにどのような処理が実行されるかを出力し、安全なテストと迅速なフィードバックを可能にする
- 開発者はこれにより設定やアクセス可否、システム状態を即座に確認し、日常的な検証ツールとして活用できる
- コード内で
dryRun フラグを確認しなければならない多少の複雑さの増加が欠点として挙げられている
- 命令型アプリケーションでは
--dry-run 機能が非常に有用であり、プロジェクト初期に導入するほど開発効率が高まる
背景
- 新たに開発中の レポート生成アプリケーションは、平日ごとに毎日レポートを生成し、それを圧縮して sftp サーバーにアップロードし、エラー応答を確認して通知メールを送信する構成
- 各段階で生成されたファイルとフィードバックファイルは、段階ごとに異なるディレクトリへ移動される
- 開発初期に、Subversion と複数の Linux コマンドの
--dry-run オプションを思い出し、同じ機能を追加
- このオプションは実際の変更を行わずに、実行時に何が起こるかを出力する
--dry-run 実行時には、生成されるレポートと除外されるレポート、圧縮および移動されるファイル、sftp でアップロードおよびダウンロードされる対象ファイルを段階ごとに出力
活用と利点
- 開発およびテストの過程で毎日使うほど有用な機能
- 実行前の状態確認用として使うと、設定やアクセス可否、システム状態を即座に確認できる
- レポート状態ファイルの日付を変更した後、そのレポートが生成されるかどうかを 即座に確認できる
- 実際のレポート生成には時間がかかるが、dry-run は迅速なフィードバックを提供する
- システム全体のテスト時にも 高速な検証ループを提供
欠点
- コード内で
dryRun フラグを繰り返し確認しなければならないため、多少コードが汚れる
- 主な段階ごとにフラグを検査し、実際の実行の代わりにログだけを出力する
- ただしこの確認は深い階層には及ばず、レポート生成ロジック内部では別途の処理は不要
結論
- 命令的に実行され結果を生成するアプリケーションは
--dry-run オプションと相性が良い
- 一方で、メッセージを待つ反応型アプリケーションには適していない
- プロジェクト初期に追加したことが 開発効率の向上に大きく役立った
- あらゆる状況で必要な機能ではないが、適切な場合には非常に有用なツールと評価される
1件のコメント
Hacker Newsのコメント
状態を持つシステムとやり取りする場合、
--dry-runにも 競合状態(race condition) が起こりうる現在の状態でツールが「何をするか」を示しても、実際の実行時には状況が変わっている可能性がある
そのため私は Terraform の
planモード方式を好む。このモードでは実行可能な計画を作成しておき、計画時点の前提が変わっていたら中断またはロールバックできるまた、コード中のあちこちに
if dry_run:を入れずに済み、計画と実行を分離してexecute(plan())の形に単純化できるDNS Planner と Enactor の間のタイミング問題により、古い計画が最新の計画を上書きしてしまった
関連する話は 以前の HN スレッド でも扱われていた
計画モードを作るにはドメイン固有言語やデータ構造が必要だからだ
(1) ファイルシステムの状態をキャプチャして計画を保存 → (2) 状態が変わっていないことを確認してから実行し、ログを記録 → (3) 以前の状態と比較してデータ損失がないか検証
この 3 段階をそれぞれ別のスクリプトやフラグとして分離して使っている
rmコマンドにこうした計画モードをどう適用できるのか気になるあるツールに
--dry-runがないときは、自分で作って使うこともあるたとえば複雑な
sedコマンドを実行する前に、diffを使って変更内容をあらかじめ比較するdiff -u <(echo "hello") <(echo "hello" | sed "s/hello/hi/g")のように差分を確認できる関連する内容は 私のブログ にまとめてある
--dry-runパターンは好きだが、ドライラン経路のコードが実際の経路と同じように動作する 必要がある単に「何をするか」を出力して実際のロジックを飛ばしてしまうと、本番実行時のバグを見逃す可能性がある
データベース書き込みや API 呼び出しの直前までは同じように実行されるべきだ
ドライランは「何が起こるか」を示すものであり、実際のテストは別の領域だ
私は逆に
--commitや--executeフラグを用意して、デフォルト実行を 読み取り専用(dry) にしておく方式を好むこうすると、誤って実際の変更を起こしてしまう可能性が減る
--commitを明示したときだけ起こるので安全だった一方で
--dry-runを付け忘れて実行し、事故になったことは何度もあったデフォルトでは比較だけを行い、
--executeを使って初めて実際にハードリンクへ置き換えるこうした確認手順はミスを減らすのに効果的だ
--wet-runのようなフラグも好きだ。状況によっては、反対の意味を持つフラグのほうが直感的なこともあるDELETE-ACCOUNTを手入力しなければならない今のところ、一度も誤ってアカウントを削除したことはない
コード汚染を防ぐには、永続化(persistence) を注入可能な戦略として分離すべきだ
あちこちに
if dry_run:を入れるのはよくないむしろ本番実行を
--wet-runで明示するほうが安全だそうすればドライランかどうかの判定を 1 か所だけに集約できる — いわゆる “functional core, imperative shell” スタイルだ
rm --wet-run tempfile.tmpのように入力するのは面倒だデフォルトは実行ありにして、その代わり
--undoオプションで最後の操作を取り消せるほうがよいかもしれない--wet-runという名前は気に入らないが、デフォルトをdry-runにして、--no-dry-runを明示しないと変更が起きない方式も使ったことがあるサービスなら、実行環境(dev/prod)に応じて自動的に安全モードを選ぶのが理想的だ
記事では「初期に
--dry-runを追加したら意外と有用だった」と書かれていたが、実際にはこうしたフラグは AI コーディングエージェント(例: Claude) が自動提案することも多い
最近多くの CLI ツールが似たパターンを持つのは、こうした エージェント主導のコード収束現象 のせいかもしれない
--dry-runに触発されたと明言していたので、十分に納得できる理由だと思う私は CLI ユーティリティに
--reallyフラグを追加して、デフォルトを読み取り専用にすることがあるミス防止のため、意図的な確認手順 を要求するわけだ
--i-meant-thatフラグを持つコマンドもあったリモートマシンを削除するコマンドで、デフォルトでは 10 秒待機してキャンセルの機会を与える
幸い、このフラグが誤って使われたことはなかった
PowerShell の優れた点の 1 つは、
[CmdletBinding(SupportsShouldProcess)]を 1 行追加するだけで自動的に
-WhatIfドライラン機能が使えるようになることだ。非常に 便利な機能 だ-Confirmも同時に有効になり、ShouldProcess関数を通してユーザーの 確認しきい値 と連携できる。本当に見事な設計だ私が管理している社内 CLI では、
if not dry_run:を REST API 呼び出し部分 の中に置いているこうすると実際の呼び出しの代わりに CURL コマンドのログ を残せるので、どんなリクエストが送られるか確認できる
ただし API 間連携が複雑になるとシミュレーションは難しくなり、単純な
if not dry_run:よりはるかに複雑になってしまう私も自動化パイプライン向け CLI を多数保守しているが、このパターンをほぼすべてのツールに適用している
まずはローカルツールをきちんと作るべきだ、という主張だ
--dry-runフラグがコード全体に散らばっているなら、状態機械パターン を適用して各段階を明確に分離するのがよい