コードレビューの効率化について

こんにちは！

みなさん、コードレビューの経験はあるでしょうか？
一人で開発しているときはありませんが、複数名のプロジェクトでは、だいたいコードレビューがありますね。

私もこれまで様々なコードレビューに参加しましたが、ほとんどのコードレビューが、非常に時間がかかります。
予定時間を大幅にオーバーすることもしばしば。

なぜこんなに時間がかかるのでしょうか？

今回は、コードレビューを効率化した話について書こうと思います:slight_smile:

# コードレビューとは何か？
ほとんどの方がイメージできるとは思いますが、
まずは、コードレビューという言葉について整理しましょう。

## コードレビューで確認したいこと
参加メンバーによって変わることもありますが、私が参加したコードレビューでは、以下の点を確認していました。

- 要件や設計内容を満たすコードになっているか
- コーディング規約は守られているか
- 条件分岐や例外処理などに漏れはないか
- そのロジックにした根拠は何か
- 困っていることや懸念事項はないか
- チーム内で認識は合っているか

関係者で認識を合わせつつ、より良いコードにしていくのがコードレビューである、というのが私の認識です。

# なぜ時間がかかることが多いのか
次に、なぜ時間がかかることが多いのかについて考察します。

## 参加者間で前提条件や背景の認識が合っていない
コードレビューの参加者（レビュアー/reviewer）は、各自、様々なタスクを抱えています。
参加者の頭の中は、自分のタスクに関することが大部分を占めている状態です。
その状態で始めた場合、どうなるでしょうか？

当然、理解するのに時間がかかります。
場合によっては、異なる認識になったりします。

## 情報が整理されていない
これは発表者（レビューイ/reviewee）側の問題になるのですが、情報が整理されていないことが多いように思います。
例えば、新規作成した以下のようなファイルがあったとします。

```javascript:App.js
import React, { useState, useEffect } from 'react';
import { View, Text } from 'react-native';
import Room from './components/Room';

const App = () => {
  const [rooms, setRooms] = useState([
    { id: '1', name: 'AAAの部屋', posts: [] },
    { id: '2', name: 'BBBの部屋', posts: [] },
    { id: '3', name: 'CCCの部屋', posts: [] },
  ]);
  const [selectedRoomId, setSelectedRoomId] = useState(rooms[0].id);
  const selectedRoom = rooms.find(room => room.id === selectedRoomId);

  const fetchData = async () => {
    // データの取得ロジック
    try {
      // DBからデータを取得
    } catch (error) {
      // 例外処理
    }
  };

  const handleAddReactionToPost = async (postId) => {
      // リアクションのカウントを増やす処理
  
      // DB更新処理
  
      return xxx;
    });
  };
      
  const handleAddPostToRoom = async (text) => {
    // 新しいポストのIDを作成
  
    // 新しいポストオブジェクトを作成
  
    // 選択されたルームに新しいポストを追加
  
    // 更新後のポストリストを取得
    
    try {
      // DB更新処理
    } catch (error) {
      // 例外処理
    }
  };
    
  useEffect(() => {
    // ルームが切り替わったときの処理
  }, [selectedRoomId]);

  return (
    <View>
    {/* 表示 */}
    </View>
  );
};

export default App;
```

極端な例ですが、これを上から順に説明するとどうなるでしょうか？
1. XXX、YYY、ZZZをインポートします。
1. ルームの初期データと、選択されたルームのIDを定義します。
1. DBに接続して、データを取得します。
1. リアクションされたらカウントを増やします。
1. ポストされたらIDとオブジェクトを作って、選択されたルームに新しいポストを追加して、DBを更新します。
1. ルームが切り替わったら〇〇します。
1. 表示をするためにコンポーネントにデータを渡します。

各ロジックでやっていることは分かりますが、全体が繋がりません。
参加者は頭の中でロジックを整理するので、理解の個人差が大きく、何度も質問を受けたり、参加者によっては理解できないまま終わったりします。

# どうしたらいいのか
時間がかかる原因となっているのは、大きく分けて以下の2点。
- 参加者間で前提条件や背景の認識が合っていない
- 情報が整理されていない

これをきちんとやるだけで、大幅に時間が短縮されます。

## 前提条件や背景の認識を合わせる
たとえば、前述のコードについては以下のようになります。
- 新規の開発依頼があり、SNSアプリを作ることになりました。
- おおまかな要件は〇〇で、今回は〇〇機能についてのレビューです。

これだけで、参加者の認識が統一されます。
レビュー前にある程度のイメージができるので、理解しやすくなります。

## 情報を整理する
私の経験上、以下の順番で伝えると、理解しやすいようです。
1. 全体像を伝える
1. 処理の流れに沿ってざっくりと伝える
1. 処理の流れに沿って細かい部分を伝える

前述のコードを例にすると、以下のようになります。
1. 今回レビューをお願いするのは、SNSアプリのメインとなるファイルです。
1. ルームを選択すると、xxx()で最新データを取得し、returnで画面を描画します。
1. ポストするとyyy()でDBを更新し、リアクションするとzzz()でカウントを増やしてDBを更新する、というのがおおまかな流れです。流れとしては、これでよろしいでしょうか。（一旦確認する）
1. それでは、流れに沿って、各処理について説明します。
1. まずxxx()ですが、＜ロジックの説明。そのロジックにした根拠も伝える。＞
1. 以下、繰り返し。

だいぶイメージしやすくなったのではないでしょうか。

ロジックの説明についても同様で、おおまかな流れと、要点でロジックの根拠を説明するといいです。

# どのくらい整理したらいいのか
もちろん、情報整理するための時間が必要になります。
忙しくてそんな時間確保できないよ、という方も多いと思います。
しかし、後のことを考えると、きちんと情報整理した方が圧倒的に楽になります。

私はレビュー前に、だいたい30分くらいかけて情報整理するようにしてます。

# 本当に効率化できるのか
確実に効率化できます。
私の経験上、レビュー時間が1/3から1/4に短縮されます。

例えば、今まで1時間かかっていたレビューが15分から20分で終わるようになります。

なにより、参加者がレビューによる疲れを感じなくなるので、チーム全体の効率化が期待できます。

# そんなにメリットある？
あります。
よく考えてください。コードレビューは、今後もずっとあります。
情報整理にも時間が必要ですが、効果は絶大。

誰もが大変さを感じるコードレビューの効率化によって、チームが活き活きとします。
明るい開発現場となるのは間違いないです。

そして、情報整理や伝え方がうまくなることで、様々な場面でビジネススキルとして発揮されます。

# まとめ
今回はコードレビューの効率化について書きました。

コードレビュー自体はエンジニア的要素なのですが、そこで一番求められるのは、情報整理や伝え方など、技術とは直接関係なさそうなビジネススキルなんです。

技術を磨いていくのはもちろんですが、社会で求められるビジネススキルも磨くことで、エンジニアとしての市場価値がさらに高くなっていくのではないでしょうか。

私もまだまだ勉強中なので、みなさん一緒にがんばりましょう！:smiley: