![見出し画像](https://assets.st-note.com/production/uploads/images/75343757/rectangle_large_type_2_a43702c52c540cd804dcbf592cdb644f.png?width=800)
【DevOps】開発スピードの高速化における Pull Request のレビューの計測と分析
CyberZ でエンジニアをしている野見山と安田です。
私たちは普段は OPENREC.tv の開発メンバーとして所属しておりますが、 その一方で DevOps の技術向上のためにチーム開発における改善の取り組みも行っております。
今回は、開発スピードの改善の取り組みの一つである、トランクベース開発の推進にあたり、浮かび上がった課題や、課題を解決するために作成した計測基盤を活用した取り組みを行いましたので、ご紹介できればと思います。
現状の課題
OPENREC.tv の開発チームでは、開発スピードの改善を行う為に DevOps の一つである、トランクベース開発の導入を推進しています。トランクベース開発の導入に伴い、現状の問題として PullRequest (以下、 PR ) のレビューやマージにかかるリードタイムが多く発生していました。
元々 PR によるレビューを行う文化はあったのですが、その PR の粒度や頻度は各メンバーに任せていました。そのため1件の PR の変更した行数が 1000 を超えることも日常的に存在し、同じ指摘が1件の PR の中で何箇所も必要になったり、一つの指摘が影響し全体のロジックの修正が必要になったりと、結果的に開発完了までの時間が長くなる傾向にありました。その結果、開発スピードが低下し、機能リリースを行う頻度も長くなっています。
トランクベース開発とは
トランクベース開発とは、開発チームがバージョニングを使用して共同作業を行う場合の開発手法の一つです。通常、開発者はトランクからブランチを作成し作業を分離して行い、機能の準備が完了したらブランチをトランクにマージします。トランクベース開発では、開発者はコードをトランクに直接 push します 。自分の作業を小さなバッチに分割し、その作業を 1 日に少なくとも 1 回トランクにマージします。
課題の解決手法
先述した課題では、PR の粒度やレビュー頻度がメンバーにより異なるため、レビュー・マージを行うリードタイムが長くなる状態が発生しています。この状態でトランクベース開発を導入した場合に、1 日以内にレビューが完了し、トランクにマージされている状態にならない可能性があります。
そこで PR のレビュー時間の計測を行い定量的に分析が行える計測基盤の作成と、計測結果からの分析を行い、トランクベース開発導入までの開発スピードの改善を実施しました。
基盤の解説・実現方法
計測基盤
GitHub の PR からレビューの開始時間やマージされるまでの時間の計測を行うにあたり、簡易的な計測基盤として以下の構成で作成を行いました。
GitHub GraphQL API v4 (以下、GraphQL API) を用いた GraphQLでの情報取得
Google Apps Script (以下、GAS) を用いた定時トリガーと情報の取得
この二つを組み合わせて実行したものをスプレッドシート上に記載してデータの収集を行っています。
![](https://assets.st-note.com/img/1648612715305-LQ8RRKMwRP.jpg?width=800)
この計測基盤を用いることで、どれくらいPRがマージされるまでに時間が掛かったか、またレビューが始まるまでにどれくらい時間が掛かったかが分かるため、開発効率の改善を行うための現状指標を確認することが可能になります。
![](https://assets.st-note.com/img/1648612863912-uzzWzslBro.jpg?width=800)
![](https://assets.st-note.com/img/1648612863923-2s4kJigFTC.jpg?width=800)
GraphQL API を用いた GraphQLでの情報取得
GraphQL APIを利用するためには GitHub のリポジトリへのアクセス権限が必要となります。開発本部では、リポジトリへのアクセス権限を必要なもののみにするため、 GitHub Apps を用いて権限の制御を行っています。
今回の計測基盤では、GitHub Appsに以下の権限のみを Read Only で付与して使用しています。
Repository permissions: Metadata
Repository permissions: Pull requests
Organization permissions: Members
GitHub Apps を利用した場合、GraphQL API の利用に必要な Token を取得する場合に JSON Web Token を用いた認証方法を利用して一時的な Token を作成しています。その Token を利用して Bearer 認証で各 API を取得しています。
有効期限の間は Token の利用は可能なため、GAS 上のプロパティの値として保存することで、無駄な Token 発行を防ぐことを行っています。
![](https://assets.st-note.com/img/1648612850226-GXAoXdrxTG.jpg)
GAS を用いた定時トリガーと情報の取得
GAS の定時トリガーは GraphQL API の Rate Limit を考慮しつつも、リアルタイムでの集計をする必要性はないことから 12時間に1回のペースで取得を行っています。
ここでは、新規に追加された PR が存在しているか、既存の PR がマージされた場合やレビューなど更新が行われているかを確認しています。
レビュー計測とマージ計測はそれぞれ別のトリガーで実行されており、それぞれ異なる情報を取得していますが、共通して以下の情報を取得しています。また、レビュー計測とマージ計測ではレビューの判定基準が異なっているため、レビュー結果の最初か最後の1件の情報を取得しています。
タイトル
マージ済みかどうか
close 済かどうか
作成者
作成日
マージ者
マージ日時
レビュー状態
レビュー更新日
レビュー者
ステータス
ドラフト状態
cursor
新規の PR を調べる際には PR 毎に設定された固有の cursor の値を用いてそれ以降のデータが存在するかを確認しています。
一例ですが、新規の PR を取得し、マージ時間の計測に使っているクエリは以下の形になっています。
{
repository(name: "${リポジトリ名}", owner: "${リポジトリの所有者}}") {
id
createdAt
pullRequests(orderBy: {field: CREATED_AT, direction: ASC}, first: 100, after: "${cursor}") {
edges {
node {
number
merged
mergedAt
mergedBy {
login
}
url
closed
closedAt
createdAt
author {
login
}
title
isDraft
reviews(last: 1, states: APPROVED) {
edges {
node {
submittedAt
state
author {
login
}
}
}
}
reviewDecision
id
}
cursor
}
}
}
}
レビュー時間及びマージ時間の計測について
レビュー時間の計測や・マージ時間の計測に関しては GraphQL API で取得した値から差分を取得し、スプレッドシート状に経過時間として表示できるように計算を行っています。GraphQL API から取得される時間に関しては UTCの文字列で取得され、そのままでは使用できないため、 Date.parse で秒数に直して利用しています。
また、スプレッドシート上の書式設定で経過時間を設定した場合に 1 の値が 24時間の扱いになるため、24時間単位で数値調整を行うためにセルに挿入する値を日単位になるように設定しています。
レビュー時間の計測としては以下の条件で計測を行っています。OPENREC.tv では最新のリリースブランチを開発用ブランチに取り込む場合にレビューをせずにマージを行うケースが多々あるため2種類の計算方法で計測を行っています。
レビューが行われた場合 : レビューが送信された日時 - PR が作成された日時
レビューが行われずにマージされた場合: マージされた日時 - PR が作成された日時
マージ時間の計測に関してはレビュー時間計測で行った、レビューが行われずにマージされた場合と同様な形で計算を行っています。
スクリプトのイメージとして以下のような形で行っています。
マージの計測時間に関しては下の条件からレビュー済みの項目がなくなった状態になります。
// レビュー済みの場合はレビュー日時からPRの作成日時の差をとる
// レビューせずにマージされた場合はマージの日時から差を取る
if (レビュー済み) {
time_second = (Date.parse(${レビュー日時}) - Date.parse(${PRの作成日時})) / 1000;
} else if (マージ済み) {
time_second = (Date.parse(${マージ日時}) - Date.parse(${PRの作成日時})) / 1000;
}
// セルに挿入する値の設定
reviewedTime = `=${time_second} / 60 / 60 / 24`;
最終的に計算された時間と GraphQL API から取得された情報を元に GAS 上で配列化し、スプレッドシートに行単位でデータの入力を行っています。
計測基盤の活用の取り組みについて
OPENREC.tv では Web フロントチーム、バックエンドチーム、アプリチームなどいくつかのチームでその計測基盤を導入して PR の計測を行っています。計測基盤を実際に稼働を開始し、現状の状況を収集し、トランクベース開発の改善方法をもとに、小さなバッチ開発や同期レビューを意識的に行うようにしました。そして、それらが本当に実践ができているのか、改善が進んでいるのかを調べるために、計測基盤を利用して PR のレビュー状況の可視化を行うことにしました。
実際には、 PR のマージはレビュイーが行うフローを取っているため、同期レビューにおけるレビューにかかる時間の計測には、「PR が作成された日時」から「PR の Status が Approve になった日時」までの時間を利用しました。今回は Web フロントチームの計測事例を紹介します。
以下が、計測基盤を利用し計測した時間をもとに、各 PR でレビューにかかった日数とトレンドライン、またその PR までの直近50件の PR でレビューにかかった日数の移動平均を示したものになります。
![](https://assets.st-note.com/img/1648613094841-x745a1Ci96.png?width=800)
![](https://assets.st-note.com/img/1648613095039-aT43qm8xru.png?width=800)
同期レビューの取り組みを始めてからは、レビューにかかる時間のトレンドラインは右肩下がりとなりました。半年前には 1 PR あたりレビューに平均2〜5日かかっていたところが、現在では平均1〜2日まで抑えることができるようになりました。また直近50件の移動平均を見ても、取り組みを始めてからレビュー完了時間は少なくなっている傾向が見られ、長くても3日以内に抑えられていることが分かります。
活用の取り組みからの学び
上に示した取り組みでも、実際にはすぐに効果が出たわけではなく、 小さなバッチに分割するにはどういった方法があるのか PR 上で議論を行ったり、その議論をもとに作成された PR で理想的なものがあれば例としてチーム内で紹介するようにしました。以下にその一部を紹介します。
コンポーネントの実装時には、「コンポーネントの作成」「コンポーネントに必要なデータの取得」「コンポーネントの埋め込み」を分けて Pull Request を作成すること
「開発の種類」をまたいだ PR を作成しないこと、ここで示す「開発の種類」は以下のように定義しています
機能追加:新しい仕様の機能を追加する
改善:既存の機能の仕様を変更する
不具合修正:既存の機能を仕様通りに修正する
リファクタ:既存の機能の仕様はそのままに、コードの変更を行う
これらの取り組みにより、チーム内では以下のような改善がみられるようになりました。
レビュー時間が可視化されたことにより、 PR のレビュー時間に対する意識向上
1 PR がアプリケーションに与える影響範囲の意識向上
その結果、開発スピードも改善され、より多くの機能リリースが行われる様になりました。
まとめ
GitHub GraphQL API v4 と Google Apps Script を用いて、 PR を分析するための計測基盤の作成方法と、その基盤を活用しての取り組みについて紹介しました。
計測基盤では GraphQL API と GAS を利用した形で簡易的ながらも、PRのデータ収集・計測を可能としました。また、収集・計測だけではなく、集計データを利用したトレンドラインの可視化など、データの活用も進んでいます。
PR の各種数値が可視化されたことにより、メンバーが PR を振り返り意識改革を行うきっかけになったと思います。
今後は定期的な計測と分析・振り返りを行いつつ、 PR の変更行数などより詳細な数値も分析できるようにし、開発スピードの高速化を行う為に、トランクベース開発を加速化させていきたいと思います。
この記事が気に入ったらサポートをしてみませんか?