GitHub Actions で開発リードタイムとデプロイ数を計測してダッシュボードを作っている話

はじめに

こんにちは。エンジニアの中畑(@yn2011)です。

今年の4 月から現在のチームでテックリードの役割を担うようになり、開発チームのパフォーマンスに関心を持つようになりました。開発チームのパフォーマンスという漠然としたテーマを前に、自分は何をするべきなのだろうか?と悩みながら情報収集をしていたのですが、texta.fm #5 AccelerateFour Keys と呼ばれる開発組織のパフォーマンス指標(と書籍「Lean と DevOps の科学」)について知り、「これは良さそう」と思い開発チームに導入してみることにしました。

今回は開発チームが Four Keys 運用の最初の一歩として、どのような技術を利用して計測と可視化を実現したかご紹介させて頂きます。

なぜやるか

Four Keys は既にユーザに対してプロダクトを公開し、継続的なリリースを行っているチームを前提としていると認識していますが、 私のチームでは新規開発を行っていて、まだプロダクトを公開していません。 とはいえ、新規開発においても開発の生産性や健全性に関心を持つことは重要だと考えています。開発チームのパフォーマンスを定量で語れる状況を作ることで、解くべき課題を明らかにし、チームが行った改善の結果を正しく認識することができます。

Four Keys をツールとして捉えれば、新規開発を行っているチームにおいても有用なのではないかという仮説の元、 本質を見失わない程度に Four Keys の定義をチームに合うように変更することで、新規開発においても開発チームのパフォーマンスを定量化できるはず、と考え導入の検討を始めました。

何から始めるか

まずは、現在のチームの Four Keys を計測し可視化する仕組みが必要です。Four Keys の運用は私やチームにとって初めての試みなので、最初から大掛かりな計測と可視化の仕組み(システム)を構築するのではなく、できるだけ小さく始めようと計画しました。

そこで、Four Keys のうち開発リードタイムとデプロイ数の 2 つの指標に絞ることにしました。変更障害率とサービス復元時間は取得が難しいことと、プロダクトを公開していないのでそもそも定義できないというのが理由です。システムのアーキテクチャも GitHub Actions と GitHub Pages を使った簡易的な構成から始めてみようと考え、開発を開始しました。

対象とする指標については、新規開発であることを考慮して以下の定義としました。

  • 開発リードタイム: コミットしてから main ブランチにマージされるまで
  • デプロイ数: main ブランチにマージした回数(main ブランチにマージすると開発環境向けのビルドとデプロイを行うため)

システム構築

今回は以下の機能を持つシステムを構築しました。

  • スケジュール実行できる
  • 対象のリポジトリから開発リードタイムとデプロイ頻度を収集する
  • 収集したデータを元に指標をダッシュボードとして Web に公開する(ただし社内メンバーのみアクセス可能)
  • ダッシュボードの更新を Slack 通知する

以下にシステム概要図を示します。

それでは、システム概要図を元に詳細についてご紹介します。

リポジトリ

データ収集対象のリポジトリとは別に、Dashboard 用リポジトリを新たに作成しました。Dashboard 用リポジトリでは、GitHub Actions を利用して以下を行っています。

  • リポジトリからのデータ収集
  • Dashboard 作成

GitHub Actions でスケジュール実行する

指標は 1週間の中央値や平均値で算出したいので、データの収集と Dashboard の更新は週に 1 度だけ実行します。

例えば、毎週月曜日の日本時間 9 時に実行する場合は以下のように記述します。スケジュール実行に加えて、手動で実行したい場合のために workflow_dispatch: も含めておくと便利です。

// actions.yaml
on:
 schedule:
  - cron: '0 0 * * 1'
 workflow_dispatch:

収集する

shibayu36/merged-pr-stat を利用して、開発リードタイム(コミットから main ブランチマージまでの日数)とデプロイ頻度(PR のマージ数)を取得します。(main ブランチにマージした際にビルドとデプロイを実行しているのでデプロイ数は PR 数と同等と見なしています)

後続のダッシュボード生成で利用するため、取得した結果は JSON ファイルとして出力します。

今回は「小さく始める」というコンセプトで開発しているので、 1 度取得したデータを永続化せず、GitHub Actions を実行する度に全てのデータを再取得することにしました。当然時間の経過と共に GitHub API のリクエスト数は増えてしまいますが、まだプロジェクトの開始から3ヶ月程度しか経過していないのでしばらくは大きな問題にはならないだろうという判断です(とはいえそのうち何とかしたい)

ちなみに、基準日から 7 日間毎のデータを繰り返し取得するため、zx でスクリプトを書いて merged-pr-stat を実行しています。

実装イメージ

while (startDate.add(7, "day").isBefore(now)) {
  // ...省略
  await $`GITHUB_TOKEN=${process.env.GITHUB_TOKEN} yarn merged-pr-stat --start=${isoStartDateTime} --end=${isoEndDateTime} --query="repo:mediba/repo-name"`.pipe($`tail -n +2`);
}

※補足ですが、コミット日時がコマンド引数に与えた対象期間外でも PR マージが対象期間に含まれていれば計測対象になります。

zx を使うことで、JavaScript から直感的に分かりやすくシェルスクリプトを実行し、その結果を利用することができます。また、ESM に対応しているため top level await が使える点も便利です。今回は利用していませんが、Promise.all でコマンド実行を並列化することで処理速度を上げることもできそうです。

可視化する

出力した JSON ファイルを元にグラフを描いて Next.js で SSG します。react-chartjs-2 を利用して以下のようなグラフを作成しました。

参考用に実装例を掲載します。

PR 数のグラフの場合は、以下のようにオプション(軸ラベル)とデータセットを定義し


  // 軸の設定
  const prOptions = {
    ...options,
    scales: {
      x: {
        title: {
          text: "週",
          display: true,
        },
      },
      y: {
        title: {
          text: "PR数",
          display: true,
        },
      },
    },
  };

  // x 軸の目盛りラベル
  const labels = json.map((d) => `${d.startDate} 週`);
  
  // データセット
  const prs = {
    labels,
    datasets: [
      {
        label: "1日にマージされた PR 数の週平均",
        data: json.map((d) => d.count / 7),
        borderColor: "rgb(53, 162, 235)",
        backgroundColor: "rgba(53, 162, 235, 0.5)",
      },
    ],
  };

Line コンポーネントに受け渡せば OK です。

<Line options={prOptions} data={prs} />

GitHub Pages にデプロイする

peaceiris/actions-gh-pages を利用して、生成したダッシュボードを GitHub Pages にデプロイします。GitHub Actions は main ブランチで実行し、SSG で生成したディレクトリを gh-pages ブランチにコミットします。

通知する

最後にダッシュボードの更新を Slack に通知します。今回は使い慣れていたので rtCamp/action-slack-notify@v2 を利用しました。

継続的にチームメンバーへ共有することで Four Keys に対する意識が高まっていきそうです。

まとめ

GitHub Actions と GitHub Pages を利用して、定期的に開発リードタイムとデプロイ頻度を収集し可視化する仕組みを作ることができました。

今回は Four Keys に対する取り組みの技術面をご紹介しましたが、今後は新規開発チームで Four Keys を計測・可視化する仕組みを導入した結果、どのようなメリットやデメリットがあったのか等開発プロセスとの関わりについてもご紹介できればと思います。

最後までお読み頂きありがとうございました。