高速なフロントエンド開発のためのセルフレビュー

高速なフロントエンド開発のためのセルフレビュー

背景

新人開発者の頃、運よくコードレビューを受けられる環境で開発を始めました。最初は、レビューの基準が何なのかもよく分かっていませんでした。単に機能が正常に動作すれば開発は終わりだと考えており、レビューで指摘される内容も、当初は些細なことに感じていました。

importの順序や変数名のように、機能とは直接関係がなさそうな部分について、次のような質問を受けることがありました。

  • 「この状態値は本当に必要ですか?」

  • 「watchで処理していますが、イベントで処理したほうが適切ではありませんか?」

  • 「このコンポーネントは責任を持ちすぎていませんか?」

  • 「null、undefined、空の配列を適切に処理できていますか?」

最初は、一つひとつ修正するのが面倒に感じることもありました。しかし、チームでの開発や運用中のサービスを実際に経験する中で、少しずつ考え方が変わっていきました。「今、機能が動作しているか?」で終わるのではなく、「このコードを別の人が再び修正することになったら、簡単に理解できるだろうか?」と考えるようになったのです。

運用環境では、「後で問題が起きたら、別の開発者が直してくれるだろう」という考えで作業するのは困難です。チームで開発していても、自分が書いたコードを別の人が再び修正することもありますし、数か月後に自分がそのコードを再び見ることになる可能性もあるからです。

こうした経験を繰り返すうちに、過去のコードレビューで確認していた項目を、開発中にも自然と一度ずつ確認するようになりました。

もちろん、今でもすべてのコードを綿密に確認するのは現実的に困難です。特に開発スケジュールが厳しい状況では、なおさらです。そこで私が言う「セルフコードレビュー」は、精密な分析というよりも、素早く開発しながらも見落としやすい問題をもう一度確認する、最低限の検証プロセスに近いものです。

1. セルフコードレビューが必要な理由

素早く開発している状況では、機能を作って正常に動作することを確認した後、次の作業に移りがちです。開発速度だけを考えれば、効率的な方法かもしれません。しかし、開発が速ければ速いほど、コードを客観的に見る機会は減ります。コードを書いている当時は全体の文脈を把握しているため、不要なコードや曖昧な構造を自然に見過ごしやすくなります。

2. 機能が動作したからといってレビューが終わったわけではない

画面が正常に表示され、ボタンを押したときに望んだ結果が表示されれば、開発が完了したように見えます。しかし、実際のサービスには正常な状況(Happy Path)だけが存在するわけではありません。APIリクエスト一つを見ても、さまざまな状況を考慮する必要があります。

  • 正常なレスポンス → データを表示

  • API失敗 → エラー処理

  • レスポンスデータなし → Empty状態

  • undefined / null → データの存在確認と安全な処理

  • 連続クリック → 重複リクエストや状態の不整合を防止

セルフレビューでは、単に「正常に動作するか?」で終わらせず、「異常な状況でも画面が崩れないか?」を確認する必要があります。

3. 1回目のレビュー:不要なコードを探す

最初に見る部分は、意外にもシンプルです。「このコードは本当に必要か?」

① 使用していない変数とimport

テストのために残したconsole.log()や、もう使っていない変数、importされたモジュールがないか確認します。こうした部分は、ESLintのような静的解析ツールの助けを借りて自動化するのがよいでしょう。

② 重複コード

複数の画面で同じAPI呼び出しとエラー処理を繰り返しているなら、共通化する必要がないか検討します。ただし、無条件に共通化すればよいというわけではありません。「このコードを共通化したとき、実際に保守しやすくなるか?」を基準に判断します。

③ 過剰な状態値

// ❌ AS-IS
const dataList = ref([]);
const isEmpty = ref(false);
const hasData = ref(false);
// ⭕ TO-BE
const dataList = ref([]);
const isEmpty = computed(() => dataList.value.length === 0);한 상태값

上記のようにdataListだけで計算できるisEmptyやhasDataのような値を、別の状態(ref)として管理する必要がないか、まず検討できます。

状態を別に管理すると、データを更新するたびにisEmptyやhasDataの値も手動で一緒に更新する必要があります。状態更新ロジックの一つでも漏れると、実際にはデータが存在するのに、画面には「データがありません」と表示されるバグが発生します。computedを活用して元のデータに依存して動作するようにすれば、状態値を手動で同期する必要がある部分を減らし、開発者が状態の更新を漏らす可能性も低くできます。

4. 2回目のレビュー:コンポーネントの責任を確認する

最初は単純だったコンポーネントも、開発が進むにつれて、ユーザー検索、認証、フォーム検証、モーダル、ページングなど、数多くの責任を抱えるようになります。

大きなコンポーネントを見たら、機能ごとに領域を分けて、独立して切り出せるか検討します。ただし、コードが長いという理由だけで無闇に分割すると、ファイルを探す手間が増えるだけです。重要なのは「小さくすること」ではなく、「責任を明確にすること」です。

PropsとEmits:親があまりにも多くの状態を直接制御していないか、イベント名だけを見てもどのような動作か推測できるかを確認します。

5. 3回目のレビュー:状態と例外的な状況を確認する

個人的には、セルフレビューで最も重要視している部分です。画面は正常な状況よりも、例外的な状況で簡単に崩れます。

① LoadingとErrorの状態

データを読み込んでいる間、ユーザーにフィードバックが提供されているか?(連続クリックの防止)

APIが失敗したとき、画面はどのように処理されるか?(ユーザーが空白の画面に取り残されないか?)

実際にあるプロジェクトのコードレビューを行った際、認証プロセスで特定のエラーが発生したときに例外処理が抜けており、画面全体が真っ白になって、その後の手続きを進められない問題を発見したことがあります。正常な認証フローでは問題がなかったため、正常なケースだけを確認していたら見落としやすいエラーでした。この経験以降、API呼び出しのコードを見るときは、成功したときの結果だけでなく、「ここで失敗したら、ユーザーはどのような画面を見ることになるのか?」も併せて確認するようになりました。

② EmptyとNull / Undefined

データが空の配列([])である状況(Empty State)と、APIが失敗した状況は異なります。また、user.profile.nameのような参照でprofileが存在しない可能性を考慮しないと、ランタイムエラーによって画面が正常にレンダリングされないことがあります。

6. 4回目のレビュー:非同期処理とAPI呼び出しを確認する

重複呼び出し:ページに入ったとき、watchが動作したとき、ユーザーイベントが発生したときに、同じAPIを不必要に呼び出していないか確認します。

非同期処理の順序(Race Condition):ユーザーが素早く2回アクションを起こしたとき、後からリクエストしたデータが先に到着し、以前のリクエストのデータが遅れて到着することで、最新の状態を上書きしてしまう可能性がないか確認します。

7. 5回目のレビュー:保守の観点から見直す

最後に、初めてコードを見る人の視点で整理します。

命名とHTMLセマンティクス: const tempの代わりに役割が分かる名前を付け、クリックイベントが必要なボタンに<div>ではなく<button>を使用しているか確認します。

コメントとデッドコード: もう使っていないコードを、何行にもわたってコメントアウトしたままにしないでください。過去の履歴はGitが覚えています。コメントでは「何を」しているかではなく、「なぜ」このように実装したのかを説明すべきです。

構造の一貫性: ファイル内でimport、props、state、methodsなどの配置が、プロジェクトの既存の記述方式と一貫しているか確認します。

プロジェクトに共通のAPI処理方式やユーティリティ、UIコンポーネントがすでにある場合は、新しい方式を作る前に既存の実装を確認します。

新しく書いたコードが技術的にはより優れて見えても、プロジェクトの既存パターンと異なると、かえって保守コストが増加する可能性があります。そのため新しい方式を適用するときは、「この方法のほうがよさそう」という理由だけで既存の方式を簡単に変更するのではなく、プロジェクト全体で一貫した方式として動作するかを先に確認するほうが安全です。

たとえばAPI呼び出しとエラー処理がすでに共通化されているなら、特定の画面だけ別の方式で処理していないか確認します。

8. 実際の変更内容を基準にセルフレビューする

コードを書いている途中でこれらすべてをチェックすると、かえって開発速度が落ちます。私は機能実装をまず終えた後、Git DiffやPRの変更内容のように、実際に修正されたコードだけを確認できる画面でもう一度見直す方法を好みます。

書くときは「どう実装しようか?」に集中していたなら、レビューするときは「初めて見るコードだとしても理解できるだろうか?」へと視点を切り替えます。

【最低限のセルフレビュー・チェックリスト】

  • 機能

  • 正常な入力に対して、意図したとおりに動作するか?

  • Loading / Error / Emptyの状態を処理したか?

  • null / undefinedの可能性を確認したか?

  • 既存の機能に影響を与えないか?

  • コード

  • 使用していない変数 / import / console.logがないか?

  • 不要な状態値を作っていないか?

  • 重複ロジックを確認したか?

  • コンポーネントの責務が大きくなりすぎていないか?

  • API / 非同期処理

  • 同じAPIが不要に重複して呼び出されていないか?

  • APIのエラー処理は一貫しているか?

  • 連続したリクエストによって状態が競合する可能性はないか?

  • 保守性

  • 変数と関数の名前だけを見て役割を理解できるか?

  • デッドコードや古いコメントがないか?

  • プロジェクトの既存パターンと一貫しているか?

  • 初めて見る開発者でもコードを追っていけるか?

9. 実務でのレビュー経験と現実的な妥協

新人時代にレビューを受けながら身につけたことは、その後、運用中のサービスを改善するプロジェクトでコードレビューを担当したときにも役立ちました。単にコードの問題を見つけるだけでなく、その後の修正や保守にどのような影響を与えるかも併せて見るようになりました。実際にこの過程を通じて、以前のプロジェクトで発生する可能性があったエラーを事前に発見し、修正できました。

しかし、すべてのプロジェクトで完璧な基準を適用できるわけではありません。スケジュールが厳しいプロジェクトを支援したときのことです。私自身も機能開発を担当していたため、既存のコードをすべて整理する現実的な余裕はありませんでした。このときは優先順位を決め、必要な部分から改善しました。

  1. 機能に影響を与えるクリティカルな問題

  2. 保守の直接的な妨げとなる部分

  3. 共通化したときのメリットが明確な部分

  4. 単純なコードスタイルの整理(consoleの削除、コメントの整理など、最小限にとどめる)

スケジュールが厳しいからといってすべての問題を無視すると、技術的負債となって戻ってきます。一方で、一度に完璧を目指してスケジュールを守れなくなるのも問題です。そのため状況に応じて優先順位を決め、必要な部分から改善するようにしています。

まとめ

セルフコードレビューだからといって、大げさなアーキテクチャレビューを行う必要はありません。特に迅速な開発が必要な状況なら、なおさらです。私が考えるセルフコードレビューとは、結局のところ「機能実装が終わったコードをもう一度疑って見直すこと」です。

新人時代は、コードレビューで指摘された内容を一つずつ修正しながら学びました。今でも、当時のレビューで受けた質問を、似たような状況で一度思い出すようにしています。

迅速に開発しなければならない状況なら、すべての部分を完璧に検討するよりも、5分だけでも見落としがないかもう一度確認することから始めてもよいでしょう。

Code_Latte

Site footer