プルリクエスト (PR) とは、(読んで字のごとく) 変更をプロジェクトのコードまたはドキュメントにプルするように求めるリクエストです。よく行われる変更管理プロセスであり、GitHub、GitLab、Bitbucket、Codeberg など、多くの VCS プロバイダーでサポートされています。VCS には通常、作成された PR を追跡する機能、変更のレビューを支援するツール、PR を承認または拒否する機能、承認済みの PR をマージする機能があります。
継続的デプロイメント (CD)を導入している場合、通常は、PR のマージに応じて新バージョンのサービスを本番環境に自動でデプロイするプロセスも必要になります。その場合には、効果的なレビュープロセスの導入が重要です。
変更の検証方法がわからない場合や、その変更が必要な理由も不明な場合、レビュー担当者は恐怖、不安、疑念 (FUD) を覚えるかもしれません。FUD を感じたレビュー担当者は、PR を保留して説明を求めることがあります。また、問題のないように見えるコード変更に対してさえ、さらに詳細なレビューを要求することすらあります。レビューが追加されるとサイクルタイムが伸び、レビュー担当者が行わなければならないコンテキストスイッチの回数も増え、開発スピードが低下します。
新機能やバグ修正は、レビューに合格しなければユーザーに提供できません。しかし、対策はあります。効果的な PR を作成すれば、追加レビューが発生する可能性を減らし、サイクルタイムへの影響を抑えられます。
プルリクエストテンプレートを使用する
コード変更を文字どおりにレビューするのは簡単です。コードがテストに合格する、リンターの警告が出ない、二次アルゴリズムを含んでいない、といったことを確認するだけです。しかし、複雑なコードベース (特に、規模が大きいコードベースやレガシーコードベース) では、コード変更自体ではなく、その変更の意図が問題になりがちです。コードが本番環境で意図どおり動作するかを、どうしたら検証できるでしょうか。
PR テンプレートを使うと、プルリクエストの構造を共通化できます。これで、プルリクエストのレビューに必要な情報を入力するように求めることができます。PR テンプレートは、GitHub と GitLab でサポートされています。独自のテンプレートを作成する場合に、以下のセクションを利用しましょう。
背景
変更を行う理由をレビュー担当者が理解できるように、事情を詳しく説明してください。選択した実装について説明してください (特に、選択理由が自明でない場合)。よりシンプルな実装を除外する根拠となったエッジケースはありますか。パフォーマンス上の懸念事項はありますか。新しいコードでは状態の形式が異なる場合、レガシーの状態にはどのように対応していますか。
変更のレビューをコミットごとに行うのが最善の場合、その旨をここに記載してください。レビュー時に空白文字の変更を無視してよい場合も、その旨を記載してください。
変更案
- 重要な変更点を箇条書きにしてください。
- できれば、例を示してください。
デプロイに関する考慮事項
他の人もデプロイを管理できるように、事情を十分に説明してください。
- デプロイは、特定の時間帯 (トラフィックの少ない時間など) に行う必要がありますか。
- 変更をデプロイする前に周知すべき、ユーザーの目に見える変化はありますか。
- この変更によって他のチームは影響を受けますか。他のチームはこの変更を把握していますか。
- デプロイ対象が大きなユーザーグループである場合、その前に変更のロールアウトでカナリアデプロイ戦略を使用しますか。使用しない場合、その理由は何ですか。
- デプロイ後、フィーチャーフラグを有効にする必要はありますか。ロールアウトフラグについてはどうですか。
検証
カナリアロールアウトまたは本番環境で変更を検証するための明確な手順を説明してください。
- 使用すべきメトリクスは何ですか。
- メモやその他の情報への参考になるリンクがあれば記載してください。
- ロールアウトフラグを使用する場合、その実装のための手順を説明してください。各手順での “クック” にはどれくらいの時間がかかりますか。
ロールバック
デプロイで予期せぬ問題が発生した場合、迅速にロールバックするための手順はどのようなものですか。
PR テンプレートは、PR を作成する際の参考となるようにわかりやすい文章で作成してください。上記の文言は、状況に合わせて調整してください。たとえば、カナリアデプロイを使用しないのであれば、該当部分は除外してください。デプロイのロールバックに Helm を必ず使用している場合は、テンプレートに helm rollback my-service-name
と記入しておけば、時間の節約になります。別の方法として、ロールバック手順へのリンクを用意してもよいでしょう。
注: レビュー担当者が PR のたびにサンプルテキストを読む手間をなくすために、サンプルテキストの削除を指示する文言を追加してもよいでしょう。
PR サイクルタイムを最小限に抑えるためのヒント
このセクションでは、プルリクエストを作成する人を対象に、最小限のサイクルタイムで承認を受けるための方法を説明します。コードには問題がないことを前提として、PR の内容を改善するポイントに絞って解説します。
変更の理由がわかるように詳細な事情を説明する
使用しているプランニング/チケットツールへのリンクを貼付しましょう。ただし、レビュー担当者はリンクにアクセスしない可能性があるので、リンク先を確認しなくても必要な情報を得られるようにしてください。
検証の明確な手順を説明する
変更が想定どおりに機能していることを確認するための手順を説明しましょう。カナリアステージと本番環境へのデプロイ後についても説明してください。
本番環境での変更の検証方法を考えると、変更の作り直しが必要になるかもしれません。変更を検証するためだけの新しいメトリクスやログステートメントも、遠慮せずに追加しましょう。後でいつでも削除できます。関連情報をまとめられる便利なダッシュボードがない場合は、カスタムの Datadog ノートブックを作成して、リンクしましょう。
初めにコードを実装する時点で検証方法をあらかじめ考えておくと、あなた自身のサイクルタイムも短縮できます。
ロールアウト形式のフィーチャーフラグの使用を検討する
フィーチャーフラグを使用すると、影響範囲を限定 (トラフィックの 1%、10%、50% など) して機能をロールアウトできます。また、コードによって生じた影響を、コードをロールバックせずに即座に取り消すことができるのも重要な点です。
フィーチャーフラグはリスク管理に有用です。ただし、古いフラグを整理するには手間と訓練が必要になるため、すべての変更に活用するのは控えた方がよいでしょう。フラグをきちんと整理しないと、一瞬で多大な損害が生じるおそれがあります。
レビューしやすいように変更をいくつかのコミットに分ける
いつでも、コミット履歴は見やすい状態に保つようにしましょう。レビュー担当者の作業がやりやすくなるのであれば、1 つのコミットを複数のコミットに分割します。一般的に、同じコードに対して複数のリファクタリングを別々に行う場合、この方法が効果的です。
空白文字への変更を無視する
空白文字への変更を無視すべき場合は、その旨を伝えるようにします。URL に ?w=1 を付けて、差分へのリンクを示してもよいでしょう。PR のレビューを “突然” まかされた場合、空白文字への変更を無視してよいかはっきりとわからないことがあります。また、経験の浅いレビュー担当者は無視するという選択肢に気付かないかもしれません。
コード変更で既存コードのインデントレベルを変更した場合 (例: if/while/for 制御構造でラップしてインデントが変わった場合)、その旨を伝えることでレビュー担当者の負荷を減らせます。
プルリクエストの実例
以下に、PR の例を 2 つ示します。1 つは悪い例で、もう 1 つは詳細で有用な例です。
悪い PR の例
タイトル: ホームページへの変更
変更点:
- ホームページの画像に変更を加えました。
デプロイ:
- 都合が良い時にマージしてデプロイしてください。問題は起こらないはずです。
検証:
- ホームページで画像の読み込み速度が速くなるかどうかを確認してください。
ロールバック:
- わかりません。変更を取り消してはどうでしょう?
上記の PR では、事情の説明が不適切であり、変更案の説明がなく、検証手順の指示が不十分で、明確なロールバック計画も記載されていません。レビュー担当者から説明を求められ、サイクルタイムが伸びる可能性が高いでしょう。
良い PR の例
タイトル: ホームページの画像読み込みの最適化
背景:
高解像度画像の読み込みが原因で、ホームページのページ読み込みに問題が発生していました。この PR は、画像の遅延読み込みを実装して、この問題を解決することを目的としています。新しい方法では、Intersection Observer API を使用して、ビューポートに入った画像を読み込みます。この変更により、ページの読み込み時間が短くなり、全体的なユーザーエクスペリエンスが改善します。
変更案:
- Intersection Observer API を使ってホームページに画像の遅延読み込みを実装
- Intersection Observer API をサポートしていないブラウザー用のフォールバックを追加
- 新しい画像の読み込み方法に対応するように単体テストを更新
デプロイに関する考慮事項:
- デプロイタイミングに関する希望は特になし。トラフィックが多い時間帯でも、変更がユーザーエクスペリエンスに影響することはない
- 周知すべきユーザーの目に見える変化はない
- 他のチームへの影響はなし
- フィーチャーフラグのアクティブ化やロールアウトフラグは不要
検証:
- ステージング環境では、ChromeDevTools の [Performance (パフォーマンス)] タブを使い、ページの読み込み時間が改善されることを確認してください。
- 本番環境では、ネットワークトラフィックと CPU 使用量を監視し、明らかな改善が見られることを確認してください。
ロールバック:
予期せぬ問題が発生した場合は、helm rollback image-service-name を使用して前のバージョンにロールバックしてください。
この PR は、行った変更の内容、その理由、適切にロールアウトする方法、本番環境で問題が発生した場合の対応方法をレビュー担当者が理解できるように、十分な情報を伝えています。
まとめ
サービスオーナーの立場では、PR テンプレートを使用して関連情報の提供を促すと、レビュー担当者が PR のレビューをするのに必要な背景情報を 1 回で得やすい体制を構築し、コンテキストスイッチとサイクルタイムを減らすことができます。
作成者の立場では、PR テンプレートに入力する (プロジェクトに用意されていなければ自分で用意したものを使う) 手間が追加で発生するため、最初のレビューを受けるまでの時間が長くなる可能性があります。しかし、サイクルタイムが短くなれば、PR のレビュー全体にかかる時間が短くなります。また、多くの場合、コードでのレガシーデータの処理方法や変更の検証方法など、デプロイに関する考慮事項をじっくり考えることで、コードの改善にもつながります。
PR が作成者とレビュー担当者の間を何度も行き来する事態をなくし、最小限のサイクルタイムで “承認” が得られるよう最適化すれば、計画、クリエイティブ、作業に費やす時間を増やし、問題対応にかかる時間は減らすことができます。