🤖

ステージング環境の取り合いを予防するCLIツールをClaude Codeで開発してみました

に公開

はじめに

こんにちは、ダイの大冒険エンジョイ勢の@bun913です。

皆さんは、ある程度規模が大きくなったシステムにおいてこんな体験をしたことはありませんか?

私「機能検証のテストのためにステージング環境を利用します!デプロイ注意してください!」
優しい同僚「OKです!」

しばらくして

優しい同僚「あっ。dependabotの修正良さそう。マージ完了!」
私「えっ。ステージング環境変わった?」
優しい同僚「あっ!!ごめーん!!」

規模が小さいうちは、ちょっと声掛けすれば十分かもしれませんが、ある程度大きい規模のチームになると当然うっかりマージして自動デプロイが走る可能性が高くなりますよね。

このような問題に対して、「できるだけお金をかけずに、かつデプロイを阻害しない形でデプロイを調整するツールが欲しいな」と思い、噂の Claude Code を使って数時間でnpmパッケージを開発・公開してみました。($100の有効活用です)

そこで、この記事の前半では公開したパッケージの使い方やイメージを紹介し、後半ではClaude Codeを効果的に活用するためにやったこと・開発中に変えていったことを紹介します。

公開したパッケージ staging-coordinator

staging-coordinatorは、ステージング環境の利用調整を自動化するCLIツールです。

主な機能

あらかじめ予定管理用のスプレッドシートに「どのシステム」の「どの環境」を「いつからいつまで」利用するかを登録しておくことで、デプロイ時点で誰かの利用予定があるかを確認します。

以下のような予定管理用のスプレッドシートを用意しておきます。

Sheetの例

以下のように CLI コマンドを実行します。

npx staging-coordinator sample-api staging

なお、以下のようにスプレッドシートのURLやSlackのTokenなどを環境変数で渡せます(パラメーターとして渡すことも可能です)。

# Google Sheets Configuration
GOOGLE_SPREADSHEET_ID=hoge # スプレッドシートのID
GOOGLE_SHEET_NAME=Sheet1 # スプレッドシートのシート名
GOOGLE_SERVICE_ACCOUNT_JSON='{}' # JSON形式のサービスアカウントキーを指定

# Slack Configuration
SLACK_BOT_TOKEN='xoxb-hoge-fuga' # Slack Botのトークン
SLACK_CHANNEL_ID=C012345678 # 承認依頼を送るチャンネルID

# Application Configuration(optional)
APPROVE_REACTION=+1 # Slackでの承認をするリアクション
REJECT_REACTION=-1 # Slackでの拒否をするリアクション
WAIT_MINUTES=20 # 承認まで何分間待つか
TIME_ZONE=Asia/Tokyo # スプレッドシートの時間帯を示すタイムゾーン
REQUESTER_USER_ID=bun913 # 承認依頼を送るユーザーID(CI/CDなどでデプロイを行うユーザーを指定する場合に利用)

このコマンドを実行すると、実行した時のタイミングでスプレッドシートに書いてある予定を参照し、もし利用予定があれば利用予定者にSlackで承認依頼を出します。(Slack IDをスプレッドシートに書かなくても動きますが、メンションをするために利用します)

Slackに来るメッセージ

この時「承認」のリアクションを押した場合は、スレッドにメッセージが届き、CLIコマンドが正常終了するため後続のデプロイが続行されます。

OKのリアクションを押した場合

また、もし「拒否」のリアクションを押した場合は、CLIコマンドがエラー終了し、後続のデプロイが中止されます。

NGのリアクションを押した場合

なお、複数の予定が重なっていた場合は、一回のSlackメッセージで複数人に向けてメンションを飛ばします。(予定の消し忘れなどもあると思いますので)

複数人にメンションを飛ばす場合

また、意図的に誰でもスタンプを押せるようにしています。お休みの時などに困りますし、このCLIツール自体にそこまで強い強制力を持たせたいわけではないためです。

CI/CDでの利用

例えばGitHub Actionsでは以下のように利用できます。

    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: '20.x'
        cache: 'npm'
      
    - name: Check staging environment
      env:
        SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
        SLACK_CHANNEL_ID: ${{ secrets.SLACK_CHANNEL_ID }}
        GOOGLE_SPREADSHEET_ID: ${{ secrets.GOOGLE_SPREADSHEET_ID }}
        GOOGLE_SHEET_NAME: ${{ secrets.GOOGLE_SHEET_NAME }}
        GOOGLE_SERVICE_ACCOUNT_JSON: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_JSON }}
        APPROVE_REACTION: "+1"
        REJECT_REACTION: "-1"
        WAIT_MINUTES: 20
        TIME_ZONE: "Asia/Tokyo"
      run: |
        npx staging-coordinator sample-api staging
    - name: Deploy to staging
      run: |
        /deploy/command

staging-coordinatorは否認のリアクションを受けるかタイムアウトの場合はエラーコードで終了するため、ここでエラーが発生した場合は後続のデプロイを行わないようにできます。

パッケージのコンセプト / 反省点

「できるだけこの仕組みのための基盤作りにお金をかけずに、かつデプロイを阻害しない」形を意識しました。

そのため、Google Sheetsを利用してスケジュール管理し、Slackを利用した承認フローの形をとりました。また、例えば GitHub Actionsの承認用のライブラリなどを活用することもできましたが、できるだけどのようなCI/CDツールでも使えるように、CLIツールとして実装しました。

Google Sheetsを利用することで、開発者ではない方でも簡単に利用できるように目指しましたが、Google Sheets APIを利用するために、Google Cloudのサービスアカウントの作成やスプレッドシートの共有設定などの初期設定のハードルが高いことが課題と感じています。(SlackのBotトークンも同様です)

README.mdに簡単な手順を書いたのですが、ここは反省点です。

Claude Codeでの開発プロセス

ここからは初めて0から1の開発を依頼したClaude Codeとの開発について説明します。このパッケージは、最低限の機能実装までに2時間程度、そのあとに機能追加や修正を行う形で、合計4-5時間程度で開発しました。

1. ドキュメント駆動での要件整理

まず、Claude Codeの「Plan」モードを使って、後からでもコンテキストや背景を思い出してもらえるように要求を整理しながらドキュメントを書いていきました。なお、各種モードの説明などについては以下の記事が非常にわかりやすかったです。

https://zenn.dev/hokuto_tech/articles/86d1edb33da61a

最初に私のやりたいことや理由をマークダウンに軽く書いて、そこから「Plan」モードで要件を整理していきました。

temp.md
ある程度規模の大きなソフトウェア開発プロジェクトでは、以下のような問題が発生することがあります。

- 検証用環境として利用できる環境の数が限られている
- 複数の機能開発プロジェクトが同時に進行している
- ある人が、ステージング環境などを利用している時に、うっかり別の人がPull Requestをマージしてしまい、ステージング環境の機能が塗り替わる

この問題に対して、あまりお金をかけずに、かつデプロイをできるだけ阻害しない形で、予定を調整できるCLIツールを作りたいです。

基本的な想定は以下の通りです。

- Google Sheetsに予定を記入しておく
- スプレッドシートの予定を参照して、CLIコマンド実行時に誰かが利用中であればSlackに承認依頼を出す
- 承認依頼を受けた人がリアクションを押すことで、CLIコマンドが正常終了する
- 承認依頼を受けた人がリアクションを押さなかった場合は、CLIコマンドがタイムアウトして終了する
- 承認依頼を受けた人がリアクションを拒否した場合は、CLIコマンドがエラー終了する

時には「逆にどのように要求を書いておけば仕様が作りやすいかな?」といった質問を投げかけて、要件を整理していきました。

https://github.com/bun913/staging-coordinator/blob/main/docs/requirements.md

Claude Codeを使用する場合、Claude.mdファイルでプロジェクト設定を管理する方法もありますが、今後どのようなツールが出てくるかわからないので、汎用的に使えるようにdocs/requirements.mdのようにドキュメントをまとめることにしました。(これに関してはどちらが良いかは今の時点ではまだ実感していません)

また、開発方針や注意点も同様にまとめましたが、ドキュメントを分けるなどしてもよかったかもしれません(粒度やスタイルの異なるドキュメントが混在する気持ち悪さがあります)。この程度の規模のツールであれば、あまりコンテキストを忘れられるといった動きはそこまで見られませんでした。

2. 随時「Plan」モードに切り替えながらドキュメント更新 + 開発

実装フェーズでは、人間には難しいような複数の機能を同時に開発しようとするので、開発開始後は随時「Plan」モードに戻り、指示を出しつつ同時にドキュメントも更新してもらっていきました。

「一回に実装するのは一つの機能だけにして」
「必ず先に失敗するテストを書いて、TDDで実装してください」
「npm run format と npm run lint を変更のたびに実行して、エラーを直してください」

見守りながら何か大事なことを見落としてそうならば、@docs/requirements.mdを参照して。TDDで一個ずつ丁寧に確認しながら実装しようねというような指示を出して、とにかく一歩ずつ進めてもらいました。

今回は私がある程度長い時間PCの前で見守る前提で丁寧に進めましたが、もしバックグラウンドで調査タスクをお願いする場合などは、もっとまとめて指示を出しても良いかもしれません。

特にテストのタイトルや書き方については、私が判断しやすいように以下のような指示を出していたので、振る舞いを確認しやすかったです。

`test` ではなく `it` を使って。
`it` には以下の3つの情報を含めてください。

- SUT(テストの対象、関数名など)
- Whenの情報(どんな状況で)
- Thenの情報(期待される振る舞い)

また、itに全ての3つの情報を含めなくても `describe` にSUTを含めて、残りをitのタイトルに含めていいです。

また、私は基本的にテストファイルを見て振る舞いを中心に確認していたので、途中でテストの書き方についても指示を出していました。

モックを使ってユニットテストを書くのはいいですが、自分でモックした値を検証する自作自演のようなテストはやめてください。
例えばSlack APIのリクエストをモック化するのであれば、モック化した返値を検証するのではなく、「HTTPリクエストに意図した値が入っているか」「依存のライブラリに意図した引数でメソッド呼び出しをしているか」といったことを検証してください。

このように、随時指示を出しながらも指示書を更新していく形で進めていきました。

まとめ

  • Claude Codeを使って、ステージング環境の取り合いを予防するCLIツールを開発してみました
  • Claude Codeにはドキュメント駆動で要件や開発方針を整理しながら、TDDで一歩ずつ丁寧に開発してもらうのが効果的でした
    • 今回はテストファイルの振る舞いを中心に確認して、意味の少ないカバレッジだけを意識したテストは書かないように気をつけてもらいました
  • CI/CDの実装なども含めて、約4-5時間で開発・公開できました

以上、乱文ですが最後まで読んでいただきありがとうございました。

GitHubで編集を提案
Money Forward Developers

Discussion