なぜ Pull Request に Approve が付かないのか?
Pull Request がなかなか Approve されないと感じたことはありますか?私は今でも感じることがあり、特に明るくない技術領域を担当したり、時間に忙殺されて焦っていた時に度々経験しました。この記事ではそういった経験から初心に立ち返って、Pull Request を出す側として意識したいことをまとめます。
原因 (だと思っていること)
レビューが負担に感じられている可能性が高いと考えています。多くの場合、レビュワー自身もタスクを持っており、その中で時間を割いてレビューしてくれます。仕事を進めるうえで必要だとはわかっていても、どうしても腰が重い (着手しにくい) タスクってありますよね。そう感じられてしまうと、後回しになりレビューされなかったり、コメントは付いても Approve が出なかったりでタスクが前に進みません。
一方で、レビュワーの立場で考えてなるべく負担を下げることで、レビューしたくなる Pull Request をつくれるのではないかとも考えています。私の考える良い Pull Request は、以下の要素を持っています。
- 読み手を意識したコード、Pull Request になっているおり、レビューに必要な情報の過不足がない
- 意図の異なる変更が混ざっていない
- レビュワーの担当スコープが明確であり、付随して予期せぬ作業が発生しない
- 驚きが少なく、合意した方針・プロジェクトの方針に沿っている
それでは、要素別に見ていきましょう。
読み手を意識する
コードや Pull Request には必ず読み手がいます。メールやチャットを書く時もそうですが、意識するしないにかかわらず情報を取捨選択したり、言葉を選んだりしていますよね。それと同じで、コードと Pull Request にも必要な情報を必要な分だけ残します。
必要な情報を書く
リポジトリごとに Pull Request のテンプレート (.github/pull_request_template.md) が用意されているケースが多いと思います。それに加えて、本文やコメントで次のような情報を残します。
- 関連するタスク管理ツール (GitHub Issues や Notion など) のリンク
- マイルストーン (完了までの全体像と現在地)
- レビュワーに頼みたいこと
- 重点的に見てほしい
- 自信がない部分の実装
- 意見を聞きたい部分の実装
- 動作確認をお願いしたい
- etc.
- 重点的に見てほしい
- コードからは読み取れないこと (妥協点、不明点など)
- レビュワーと共通認識をつくった後に必要になった変更
レビューに必要な情報が揃っておらず、レビュワーの方からコミュニケーションを取る必要があると負担が上がります。先回りして必要な情報を残すことで、とっつきやすい Pull Request になります。
不要な情報を書かない
"何を書くか" と同様に "何を書かないか" も重要です。極端な例ですが、ペアプログラミングをしたのであればレビューに必要なコンテキストの大部分は共有できていますし、レビュワーが同じ開発チームのメンバーであれば事細かな説明は蛇足になりがちです。ここでも、読み手とどれだけコンテキストを共有できているかを意識しましょう。
書くべき情報が多すぎると感じる場合は、Pull Request のサイズが大きかったり、スコープ外の変更を行っている可能性もあります。レビュワーが見るべき箇所に集中できる環境をつくれると良いです。
AI の Pull Request 生成
最近では AI が Pull Request の作成〜本文まで書いてくれて便利です。ただ、AI 生成の本文は情報量こそあるものの、積極的に読もうとは思えません。
これは仕方がないことで、AI は開発のフェーズや進捗など、コンテキストを知る由もないからです。そのため、人に向けたメッセージは人が書いた方が良いと思っています (仮に必要なコンテキストをすべてプロンプトするとしても自分で書いた方が早そう)。
ただ、開発チームごとに "レビューに対して何を求めるか" は異なりますし、人がレビューするかという前提すら必ず当てはまる訳ではありません。Pull Request の生成自体は非常に便利なので、うまく使い分けていきたいです。
AI 生成だとわかる 🤖 Generated By Claude などのマーカーが付いていると良いのかもしれませんね。どちらにせよ、Pull Request の書き方がチームの了解になっているか、それらが混ざっていないかは意識した方が良いと思います。
サイズを小さくする
"Pull Request のサイズを小さくしろ" とはよく言われますが、しばらくの間サイズを小さくする方法にピンと来ていませんでした。なぜなら、実装前に予想できている事が少なく、「機能をつくった結果そのボリュームになった」という話になりやすいからです。これはエンジニアのスキルとも密接に関わってきますが、タスクの進め方を工夫するだけでも大きく改善できると考えています。
マイルストーンを置く
まずは、タスクを完了まで持っていくのに必要なことを書き出します。サブタスクに分解する過程で、細部が気になったり、後半のサブタスクに対して解像度が低いことに気づく事があります。これはそういうものだと思っていて、進めないと見えてこない部分もありますし、着手前に考えればよしとしています。
次に分解したサブタスクを Pull Request のタイトルをイメージしながら、くっつけたり分解したりします。最終的に、ここで決めた粒度でタスクを消化していきます。もし、マイルストーンを置ける程度にタスクの全体像が見えていないようであれば、この時点で誰かに相談するのは効果的です。後述する合意の細分化にも繋がります。
Tidy First? から学ぶ
最近 Tidy First? を読んだこともあり、振る舞いの変更と構造の変更を区別して考えるようになりました。
| 構造の変更 (Structural Change) | 振る舞いの変更 (Behavioral Change) | |
|---|---|---|
| 内容 | 観測可能な振る舞いを変えずにコードの構造を変える。リネーム、メソッド抽出、ファイル分割など | 機能追加やバグ修正など、コードの振る舞い自体を変える |
| 特徴 | 可逆的であることが多い。将来の変更コストを安くする | 不可逆的になりやすい。ユーザーに価値を届ける |
| レビュー観点 | 既存の振る舞いが壊れていないか。自動テストが整備されていれば、レビューは不要かもしれない | 仕様を満たしているか、設計は妥当か。重点的にレビューすべき |
表を見てわかる通り、振る舞いの変更と構造の変更はレビューの観点が異なります。これらを一緒くたにしてしまうと、レビュワーはコードの差分から変更の意図を抽出する必要があり、認知負荷が大きくなります。
それではボーイスカウトルールで言われるような、ついで直しは悪なのでしょうか。そうではなく、今よりコードを綺麗にして帰る姿勢はコードベースを健康に保つ上でも推奨されることです。
本の中ではこのような構造の変更を "整頓" と呼んでおり、別の Pull Request として切り出す手段もあると紹介しています。
以下はその一例ですが、最近取り入れているアプローチです。
- 整頓の Pull Request に
tidyタグを付ける - チーム内で整頓の目的とレビューの観点を合意し、整頓のレビューには時間を掛けない
これにより、Pull Request の数が増えることよりも、見るべき Pull Request に注力できるという利点が上回るため、ベロシティを維持したままコードの整頓を実施できています。実際、あるクラスに対してメソッド抽出 (Extract Method) とテストコードの追加だけを行った Pull Request のレビューを面倒だと感じると人は少ないと思うので効果は覿面です。
後々は AI レビューにしたい
整頓の Pull Request は Claude Code GitHub Actions のレビューが通っていれば良しとするなど、AI との相性も良いアプローチです。次のワークフローファイルは tidy タグが付いたら、レビューを発火する条件になっています。
name: Claude Code Review
on:
pull_request:
types: [labeled]
jobs:
claude-review:
if: github.event.label.name == 'tidy'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Run Claude Code Review
id: claude-review
uses: anthropics/claude-code-action@v1
レビュワーの負担を下げる
レビューを困難なものにする根本的な要因として、"プロジェクトで求められる品質に達していない" という事があります。ただ、これでは身も蓋もない話になってしまうので、普段から工夫している点を紹介しようと思います。
方針決めの PR をつくる
「こういった方針で実装します!」という意図を伝える Pull Request をつくることは、まだチームメンバーと設計を合意できていない場合に有効です。昨今では AI Agent があるので、このような実装の青写真をつくることは比較的に低コストでできるようになりました。
多くの不具合や設計ミスは、前提の理解から間違っていたりします。そのため、チームメンバーと細かく合意しながら設計することで、手戻りのリスクを最小化できます。また、レビュワー視点でも「予想していなかったコードがドカンと出てきた」という事態になりにくいので安心です。
慣れないうちは面倒に感じると思いますが、実装後に大きな修正が入るのはレビューイ・レビュワーの双方にとって負担が大きいです。レビュワーはサンクコストや作業進捗が気になりますし、申し訳なく思いなかなか言い出すこともできません。レビューイとしても「先に言ってくれよ」という話になりやすいです。手戻りを完全になくすことはできませんが、できる限り減らそうという姿勢が重要だと思います。
他人の頭脳を使う
15 分で解決できないことは、知っていそうな人に聞きましょう。わからないことを言葉にした上で、ドメイン知識ならドメインエキスパートですし、コードの詳細や背景を知りたいのであれば当時の担当者に聞きます。技術的なことであれば、同僚や先輩エンジニアが答えを持っているかもしれません。
もし聞ける立場の人がいないなら、腹を決めて自分で何とかしましょう。
目立たせたい部分にコメントする
自信がない・意見がほしいといったコードがあれば、気づいて貰いやすいように GitHub 上でインラインコメントを残します。レビュワーとしても目が滑って読み飛ばしにくいですし、このコメントから知見の共有や、より良い設計に繋がることも少なくありません。私としては、レビューにおける重要な要素だと捉えています。
また、Pull Request のコメントとして残すべきものと、そうでないものはしっかり区別したいです。
GitHub 上のコメントは揮発するので、積み残した課題があればタスク管理ツールに登録するべきですし、後続のサブタスクで確実に対応するのであれば TODO コメントを残すと親切かもしれません。また、次にコードを読む人へに伝えたいことであれば、コード内コメントとして書きます。
他人のコードは理解しにくいという前提に立つ
"過去の自分が書いたコードは他人の書いたコード" といいますが、昔の自分も含めて他人の書いたコードは自分で書いたコードよりも読むのが難しいです。これは、思考パターンが自身のメンタルモデルと異なるためだと思っています。反対に自分のコードであれば、予測がしやすく、読み飛ばせるので早く読めます。この溝を完全に埋めることは不可能ですし、その必要はありません。ただ、レビュワーは理解しにくいコードを読んでいるという前提に立つことは、シンプルで読みやすいコードを書く良い動機付けになります。
以下のサンプルコードは React コンポーネントですが、意図を適切な粒度で関数や説明変数として切り出すことを意識しました。これにより、読み手は名前やコメントからより多くの情報を得ることができます。
type CartItem = {
id: string;
name: string;
price: number;
quantity: number;
};
// 商品単位の小計
type CartItemSubTotal = {
id: string;
name: string;
subtotal: number;
};
// 商品単位の小計およびカート内の合計
type CartSummary = {
itemSubtotals: CartItemSubTotal[];
totalPrice: number;
};
// 注文可能な最低金額
const MINIMUM_ORDER_AMOUNT = 5000;
// 商品単位の注文可能な上限数
const MAXIMUM_CART_ITEM_QUANTITY = 100;
/**
* カートの小計と合計を計算する
* @remarks 購入する商品数が多い場合に備えて、単一のループで小計と合計を同時に計算している
*/
function calculateCartSummary(items: CartItem[]): CartSummary {
return items.reduce<CartSummary>(
(current, item) => {
const subtotal = item.price * item.quantity;
current.itemSubtotals.push({ id: item.id, name: item.name, subtotal });
current.totalPrice += subtotal;
return current;
},
{ itemSubtotals: [], totalPrice: 0 }
);
};
function Cart ({ items }: { items: CartItem[] }) {
const { itemSubtotals, totalPrice } = calculateCartSummary(items);
// 説明変数で注文可能な条件を満たしているかの Bool 値であることを表現
const canOrder =
totalPrice >= MINIMUM_ORDER_AMOUNT &&
items.every((item) => item.quantity <= MAXIMUM_CART_ITEM_QUANTITY);
return (
<div>
<ul>
{items.map((item, index) => (
<li key={item.id}>
{item.name}: {itemSubtotals[index].subtotal.toLocaleString()}円
</li>
))}
</ul>
<p>合計: {totalPrice.toLocaleString()}円</p>
<button disabled={!canOrder}>注文する</button>
</div>
);
};
Pull Request にコメントがたくさん付くことがありますが、レビュワーはわからないことに対してコメントしています。コメントが多すぎるとその対応でマージが遅れ、結果として修正〜確認 (再レビュー) やコンフリクト解消でコストが積み上がります。
そのため、疑問を持たせないようなコードが理想的です。もしコメントを貰ったら、レビュワーがどういう理由でコメントしたのか考察して、次から先回りしてコードに反映できるように工夫しましょう。
セルフレビュー
レビューを依頼する前に、自身の Pull Request に対してセルフレビューを行います。メールやチャットでも送信する前に、意図が伝わる内容になっているか、誤字脱字はないかを確認すると思います。それと同じように、読み手側の視点に立ってみる事が重要です。
自分で書いたコードを忘れて客観的に見るのは非常に難しいですが、レビュワーをなったつもりで Pull Request〜コードまでを通しで読んでみます。ここで何らかの不足に気づくことも多いため、やらないのとではクオリティに差が出ると感じています。
また、AI コードレビューを活用することで明らかなバグやタイポ、コーディングガイドラインに沿っていない箇所などは高精度で特定できます。こういった細かい粗はレビュワーのノイズになり、本来集中すべき箇所にリソースを割きにくくなるため、事前に取り除きましょう。
セルフレビューで何を見るか
視点を変えて見ることで、新しい気づきが得られるかもしれません。そのために、散歩に出かけるなどの手段はよく聞きます。私としては、細部まで重点的に見るというよりも、全体として要素が繋がっているかを見ている気がします。
また、AI コードレビューの限界も知っておくべきです。ドメイン領域の高度な判断は難しく、リファクタリングも自分から聞かないとあまり提案してくれません。対策としては、Sub Agents でエキスパートのロールを与えた AI にレビューして貰いつつ、人間が重点的にレビューすべき点を正しく認識できることかと思っています。
不安を与えない
コードレビューをしていて不安を感じると、モードが切り替わる感覚ような感覚を覚えることがあります。例えば、Pull Request にバグが目立つ状況が続いたり、コードに嘘が混じっていると警戒心が増します。
function validateCartItemCount(itemCount: number) {
// バリデーションを実行する関数内でローカルストレージへの書き込みを行っている
localStorage.setItem("cartItemCount", itemCount.toString());
return itemCount > 0;
}
// 商品単位の注文可能な上限数。正しい仕様は 100 件であるが、タイポまたは仕様の誤認識でバグっている
const MAXIMUM_CART_ITEM_QUANTITY = 10;
バグなしに収束するというのは結果であるため、エンジニアとしてはバグを絶対に出さないという姿勢で臨むのと、バグ検出の手法を知ることが重要です。
- 仕様を場合分けして、チェックリスト化する
- 予想と事実を切り分けて考える
- 自動テストについて学び、ヒューマンエラーを減らす手法を知る
- AI Agent に検証の手段を与える
警戒モードになると必然的にコードを読む量が増えるので、レビュワーのコストに時間が掛かると同時に指摘も貰いやすくなります。経験上、ここから負のサイクル (マージできない > 焦る > ミスが増える) に陥る可能性が高いので、レビュワーの不安を与えないような Pull Request を目指していきたいです。
おわりに
今回は Pull Request を出す上で意識したいことをまとめました。レビューの負荷がどんどん大きくなっている今日この頃なので、より人対人の部分を意識して仕事をしていきたいです。
フロントエンドが得意なアプリ・システム開発会社 株式会社FLAT(wd-flat.com/?utm_source=zenn&utm_medium=social)のテックブログです。
Discussion