生産性 可視化 GitHub

コードメトリクスを計測・可視化する

生産性 可視化 GitHub

今回は、データ基盤チームで進めている生産性ダッシュボードプロジェクトのサブプロジェクトとして進めているコードメトリクスを計測・可視化のための基盤について紹介したいと思います。

生産性ダッシュボードプロジェクトやその中心となるメトリクスであるFour Keysについては以下のエントリーやANDPADさんのポッドキャストでも紹介されていますのでぜひご覧ください。

  1. コードメトリクスとは何か
  2. コードメトリクスの計測・可視化のモチベーション
  3. コードメトリクスの計測
    1. 計測するメトリクスの選定
    2. 各リポジトリでの計測
    3. モノレポや並行テスト環境でのカバレッジレポートの計測
    4. 各リポジトリのコードメトリクスの計測結果を集約する
  4. コードメトリクスの可視化
    1. ダッシュボード基盤
    2. コードメトリクスダッシュボード
  5. まとめ
    1. 計測パート
    2. 可視化パート
    3. みなさんはどうしていますか?

コードメトリクスとは何か

コードメトリクスとは、ソースコードについて様々な角度から計測した値のことを指します。

具体的には、コードの行数といった単純なものから循環的複雑度のようなソースコードの特性を表す計測値などです。

また、本エントリーではテストのコードカバレッジやソースコードをとりまくプラットフォームの計測値もコードメトリクスに含むこととします。

コードメトリクスの計測・可視化のモチベーション

GMOペパボではGitHub Enterprise Server (以下、GHES)を利用しています。

各事業部や各プロダクトではGHESにリポジトリを作成しアプリケーション開発をしています。

また、CI/CD基盤としてGitHub Actionsを活用しており、テストやデプロイの自動化などが行われています。

上記のような環境の中で(時系列は違いますが)以下のようなことを実現したいと考え、コードメトリクスの計測そして可視化の基盤を構築していくことにしました。

  • 日々の開発においてコードの品質や生産性を確認するために何かしら定量的な計測値を提供したい
  • 生産性ダッシュボードのメトリクスとしてコードにフォーカスした値を継続的に観測したい

本エントリーではコードメトリクスの「計測」と「可視化」の前後半パートでお届けします。

コードメトリクスの計測

技術基盤チームの@k1LoW です。コードメトリクスの計測基盤について紹介します。

計測するメトリクスの選定

まずコードメトリクス計測の第一歩として何を計測するかを考えました。

前提として、GMOペパボの技術スタックとしてのプログラミング言語はRuby、PHP、JavaScript(TypeScript)、Go、そしてモバイルアプリ開発言語など、多様です。

取得するメトリクスとして「まず多くのリポジトリをカバーできる計測値であること」が望ましいと考え、以下に紹介する3つを採用しました。

1. コードカバレッジ

まずコードカバレッジを採用しました。

コードカバレッジは、テスティングツールがある仕様の決まったフォーマットにそったカバレッジレポートを出力します。

カバレッジレポートのフォーマットは(大抵は)プログラミング言語には依存しません。

例えばですがLCOVやCobertura XMLなどのカバレッジフォーマットが存在します。

カバレッジレポートの仕様が決まっていることと、それぞれのカバレッジレポートフォーマット間の変換ツールなども有志の方が数多く公開していたりすることから、ある程度の数のカバレッジレポートのフォーマットに対応すれば、GHESのリポジトリの大部分のプログラミング言語をカバーできると考えたのが理由です。

2. Code to Test Ratio

Code to Test Ratioは実行コードの行数に対するテストコードの行数の割合です。テストコードについて、コードカバレッジとはまた別の視点でみることができます。

Ruby on Railsを使って日々開発している方には rake stats コマンドが出力する値の1つとして慣れ親しんでいる計測値です。

こちらは @hsbt からアイデアをもらい検討をしました。Railsの体験を他のリポジトリにも輸入できる(同一の指標を提供できる)ということで提供することには大いにメリットがありそうです。

実装面においては、Code to Test Ratioはまず各プログラミング言語のLOC(Line of Code)を計測できる必要がありますが、LOCの計測には先行実装やライブラリが多くあることから採用しました。

3. テスト実行時間

テスト実行時間は開発の生産性に関係する値です。

テストを実行する時間が短ければ短いほど開発のライフサイクルが早くなるのは明らかです。逆にテスト実行時間が長いと「テスト待ち」が発生することで開発者の開発体験にマイナスの影響があります。

Four Keysにおいても特に変更のリードタイム(Lead Time for Changes)にも影響がありそうです。

テスト実行時間をどう計測するかですが、これはほぼ全てのリポジトリのCI環境としてGitHub Actionsを採用していることから、GitHub API経由で実際にテストを実行しているstepの実行時間を取得することで可能だろうと考え採用しました。

各リポジトリでの計測

上記3つのコードメトリクスを取得できるツールとして octocov を開発し、GitHub Actions上のActionとして使えるようにしました。

各リポジトリでは、まずテスティングツールにカバレッジレポートを出力してもらうようにします。

そして、octocovの設定ファイル( .octocov.yml )を設置した上で、テストを実行しているWorkflowで octocov-action を呼び出せば、octocovがコードメトリクスを計測し、Pull Requestにレポートを追加してくれるようになります。

Pull Requestへのコメント

例えばGoアプリケーションの .octocov.yml と WorkflowのYAMLファイルは以下のような感じになります。

# .octocov.yml
coverage:
  # カバレッジが70%未満だったとき処理がexist status 1で終了する
  acceptable: 70%
codeToTestRatio:
  # Code to Test Ratioが1:1.1未満だったとき処理がexist status 1で終了する
  acceptable: 1:1.1
  # 実装コードとしてカウントするソースコードを指定。GitHub Actionsの `paths:` の設定と同じような動きをします
  # See https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#example-using-positive-and-negative-patterns-1
  code:
    - '**/*.go'
    - '!**/*_test.go'
  test:
    - '**/*_test.go'
testExecutionTime:
  # テスト実行時間が3分を超えていたとき処理がexist status 1で終了する
  acceptable: 3 min
diff:
  # コードメトリクスの差分を計測するときの比較元データストア
  datastores:
    - bq://project-xxxx/xxxx/github_coverages
comment:
  if: is_pull_request
report:
  if: is_default_branch
  # コードメトリクスのレポートを保存するためのデータストア
  datastores:
    - bq://project-xxxx/xxxx/github_coverages
# .github/workflows/ci.yml
on:
  push:
    branches:
      - main
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    env:
      GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    steps:
      - uses: actions/setup-go@v2
        with:
          go-version: 1.18

      - uses: actions/checkout@v3

      - name: Run tests
        run: make ci

      - name: Run octocov
        uses: k1LoW/octocov-action@v0

モノレポや並行テスト環境でのカバレッジレポートの計測

一番シンプルなリポジトリだと単一アプリケーションで単一のシーケンシャルなテストになりますが、アプリケーションによってはモノレポを採用していたり、テスト実行時間短縮のためにGitHub ActionsのWorkflowで並行テストを実行している場合もあります。

上記のような環境にも対応できるようにしています。

具体的には、

  1. モノレポ用に、カバレッジ計測レポートを owner/repo だけでなく owner/repo/sub のように .octocov.yml で設定できるようにすることで集計を別にできる機能
  2. octocov のコードメトリクス計測結果の出力機能や、octocovのレポートだけでなく、サポートしているカバレッジレポートのマージ機能
  3. 並行にテストを実行しているstep名を列挙することで、並行実行されている重複時間を考慮したテスト実行時間計測機能

などを機能として提供しました。

例えば、並行テストの設定例としてはoctocovのリポジトリの例をご覧ください。

各リポジトリのコードメトリクスの計測結果を集約する

さて、ここまでの説明だとリポジトリごとにコードメトリクスを計測してPull Requestにコメントをするまでですが、実は .octocov.yml の設定にある datastores: をうまく設定することで、各リポジトリのコードメトリクス計測結果を集約することが可能になります。

上記の .octocov.yml の例だと bq://project-xxxx/xxxx/github_coverages 、つまりBigQueryのテーブルをoctocovのデータストアとして使用しています。

全てのリポジトリで同一のデータストアを指定することで、各リポジトリのコードメトリクス計測結果を集約しています。

ここまでがコードメトリクスの計測基盤の紹介になります。

コードメトリクスの可視化

2021年11月に技術部データ基盤チームに異動しました、今年で新卒3年目の @komatun です。ここからは、可視化の基盤として「ダッシュボード基盤」と、成果物の「コードメトリクスダッシュボード」を紹介します。

ダッシュボード基盤

GMOペパボでは、ダッシュボードをGHES上でコード管理するための基盤を内製しています。ペパボテックブログ記事エンジニアの活動情報からFour Keysを集計、可視化した話において、ダッシュボード基盤の構成が詳しく紹介されていますので、この記事ではoctocovで収集したデータがコードメトリクスダッシュボードに表示されるまでに絞って仕組みを解説します。

ダッシュボードを表示する仕組み

(図の一部に twemoji の画像を使用しています)

ダッシュボード基盤では、PythonのStreamlitというフレームワークを利用してダッシュボードを構築しています。Streamlitのアプリケーションとしてのダッシュボードは、BigQueryのデータを参照してグラフを生成します。

ダッシュボード基盤はGHES上のリポジトリで管理しており、ダッシュボードへの変更は必ずレビュープロセスを通ります。Pull RequestをマージするとGitHub Actionsが動きます。

GitHub Actionsは、ダッシュボードの表示に必要なコード(Pythonファイル)と集計用のSQLを、ひとつのStreamlitのアプリケーションにまとめ、Dockerコンテナに固めて、GCPのCloud Runにデプロイします。

ダッシュボードへのアクセスはGoogle Workspaceのアカウントで認証します。Google Cloud Load BalancingとIdentity-Aware Proxyによって実現しています。複数のダッシュボードについて統一して認証管理できる点が特徴です。

コードメトリクスダッシュボード

Streamlitのアプリケーションであるコードメトリクスダッシュボードは、octocovがBigQueryへ集約したコードメトリクスからグラフを表示します。リポジトリにoctocovを導入するだけで、メトリクスがBigQueryへ収集され、自動的にダッシュボードにも反映されます。

octocovで取得したメトリクスをもとに、ダッシュボードには4つのグラフを表示し、それぞれの時系列変遷を可視化しました。

  • テストカバレッジ
  • Code to Test Ratio
  • テスト実行時間
  • 実行コード行数とテストコード行数

ダッシュボードの一部

ダッシュボードの一部

ダッシュボードから「コード行数の増加に伴って、テストカバレッジが急激に落ちていないか?」「テスト実行時間が急激に増えていないか?」などを読み取ることができます。

コードに関係するメトリクスを時系列で可視化したことによって、例えばoctocovで収集している「実行コード行数」「テストコード行数」のデータから、リポジトリの規模や、活発に開発されているリポジトリかどうかといった、リポジトリの姿を把握できるようにもなりました。

コードメトリクスを可視化するためのダッシュボードの作成は、@komatun がデータ基盤チームに異動した直後にPythonを全く書いたことがない状態から着手しましたが、必要なメトリクスがBigQueryに集約され、可視化の基盤も整備されていることから、既存の仕組みに乗っかるだけで容易に実装できました。

まとめ

本エントリーでは、コードメトリクスの計測と可視化の基盤について前後半パートに分けて紹介しました。

最後に、今後実施してみたいことについても紹介したいと思います。

計測パート

現在は全リポジトリ共通で取得できるメトリクスを優先して収集していますが、各リポジトリで独自に取得できるメトリクスも収集できるようにしたいと考えています。

例えば、@ebihara99999 が開発したコードの品質に関するメトリクスの取得ができるGem のメトリクスや、データベースドキュメントのカバレッジなど、任意のメトリクスも特定のルールに従って出力されていれば合わせて収集できるようにできればと考えています。

可視化パート

「コードメトリクスダッシュボードから気づきを促す仕組み」を提供できるといいなと思っています。

例えば

  • 複数のメトリクスを照らし合わせて、「開発が盛んだがテストカバレッジやCode to Test Ratioが下がってしまっているリポジトリ」を特定し、テストを書くことを提案する
  • 急激に値が上がった/下がったタイミングのPRへのリンク(動線)を用意しておき、要因調査に役立てられるようにする

などを試してみたいです。

みなさんはどうしていますか?

みなさんのFour Keysやコードメトリクス活用事例など、ぜひ教えてください。