15
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

株式会社PRUMAdvent Calendar 2024

Day 3

【本のまとめ】新人プログラマーのためのエラーが怖くなくなる本

Last updated at Posted at 2024-11-30

まえがき

みなさま日々の学習お疲れ様です!
私はruby学習2年目のものです。
「コードが動かないので帰れません! 新人プログラマーのためのエラーが怖くなくなる本」という本を読んでためになったと思う箇所をかいつまんで文章にしてみました。参考になれば幸いです。

ざっくりとした本の内容

プログラミングをしている人であれば、誰しもこんな場面を経験したことはないでしょうか?

「コードがエラーで動かない!」
「エラーの原因がどこにあるのかわからない!」
「何をどうやっても不具合が解決できない!」

どんなにキャリアを積んだプログラマーでも、プログラムのエラーや不具合を完璧に防ぐのは難しいものです。そのため「エラーや不具合の原因をすばやく見つける技術」は、プログラミングをする上で欠かせないスキルの1つです。

本書は、そんな「コードが動かない!」という状況でどのように対処したらよいのか、エラーや不具合との上手な付き合いかたを、新人プログラマー向けにやさしく解説する入門書です。

amazon URL

1. なぜエラーを読みたくなくなるのか

エラーに対して苦手意識を持つ人も多いはず。そんな人はなぜエラーが苦手なのかという原因を知ることでエラーへの恐怖心を克服することができる。

  1. 英文は読みたくなくなるが意外と簡単

    1. 具体例
      1. 〇〇 is not defined = 〇〇は定義されていません。
      2. 〇〇 is not a function = 〇〇は関数ではありません。
      3. 〇〇 is not iterable = 〇〇は繰り返し可能ではありません。
      4. Function statements require a function name = 関数分は関数名が必要です。
      5. Cannot read properties of null = nullのプロパティを読み取ることができません。
      6. Cannot set properties of null = nullのプロパティを設定することができません。
      7. Cannot use ‘in’ operator = in演算子を使うことができません。
      8. Invalid array length = 不正な配列の動き
    2. よく遭遇するエラーのまとめ
    valid/ invalid 有効な / 不正な
    expercted /unexpected 予期した / 予期しない
    defined / undefined 定義された / 未定義の
    reference 参照
    require 必要とする
    deprecated 非推奨な
    expired 期限切れの
    apply 適用する
    deny 拒否する
    permission 許可
    range 範囲
    missing 見当たらない
  2. 長文のエラーでも必要な情報は二、三行だけ。

    1. エラーの種類
      1. RefarenceErorrなど
    2. エラーメッセージ
      1. name is not definedなど
    3. スタックトレース
      1. 詳細情報

2. エラーの上手な読み方

初めのうちは多少の時間をかけてもエラーの単語を理解するようにすること。分からないからと後回しにしていたらいつまで経ってもエラーへの苦手意識を拭えない。だから、エラーの内容を理解する努力を惜しまないことが、エラー解決をする近道になる!

スタックトレース

エラーが発生するまでの処理の流れを書いたもの。
例えば、下記のようなもの。

Traceback (most recent call last):
    5: from example.rb:10:in `<main>'
    4: from example.rb:6:in `calculate'
    3: from example.rb:2:in `divide'
    2: from example.rb:2:in `/'
ZeroDivisionError (divided by 0)

スタックトレースは、最終行から上に積まれていくように処理がされていって処理が止まった最終地点が1行目に表示されるようになっているため、すべての行を読もうとせずに最終地点の1行から読んでいけばいいと考えれば気が楽になる。
これを利用して効率よくデバッグをするには、vscodeでは「移動」から15:35と入力すればすぐにエラー箇所を表示してくれる。

主なエラーの種類

  • シンタックスエラー: Syntax Error 構文エラー
  • リファレンスエラー: Reference Error 参照エラー
  • タイプエラー: Type Error 型エラー
  • ランジエラー: Range Error 範囲エラー
  • ノーメソッドエラー: NoMethod Error 存在しないメソッドが呼び出された時のエラー
  • アーグメントエラー: Argument Error 引数の数や形式が期待するものと一致しない場合のエラー
  • ランタイムエラー: Runtime Error ユーザーが自分で定義したエラーのデフォルトの型
  • ネームエラー: Name Error 未初期化の定数や未定義のメソッド名を参照した時のエラー

3. エラーの原因の見つけ方

デバッグとは、エラーの真の原因を見つけ出し修正する一連の作業です。
「デ」は取り除く、「バグ」はエラー・不具合・問題を意味します。

デバッグの基本的な流れ:

原因を探す → エラーを読む → 原因を特定する → 修正する

エラーが出ない場合の対処法:

  1. プリントデバッグ
    プログラムの状態を表示させる手法です。
    JavaScriptの場合:console.log('出力結果: ${表示したいデータ}')
    Rubyの場合:debugger
  2. 二分探索
    全体の範囲の真ん中から探索を始め、探索範囲を半分ずつ絞っていくデバッグ手法です。
  3. コメントアウト
    二分探索の考え方を用いて、コードの半分をコメントアウトし、エラーの有無を確認しながら問題箇所を特定していく方法です。
  4. 大きな単位からの切り分け
    ・フロントエンドとバックエンド
    ・サーバーとデータベース
    ・ブラウザ、ユーザー環境、サーバーサイド、データベース、インフラ
  5. Gitの活用
    変更履歴を確認し、どの時点まで正常に動作していたかを特定します。
  6. コードの段階的な変更
    ・動かないコードから少しずつ削減する
    ・動くコードから少しずつ追加する
    状況に応じて適切な方法を選択します。

効率的なデバッグの手順

・考えられる原因を箇条書きにする
・各項目を具体的かつシンプルに記述する
・重複を削除し、複数の要因は分割する
・優先順位をつけて並び替える

デバッグでやってはいけないこと

・複数の仮説を同時に検証する
→一度に一つの仮説のみを検証する
・一つの仮説に固執する
→些細な疑問点も記録し、検証する
・面倒だからと検証を諦める
→手間を惜しまず、丁寧に確認する

4. ツール活用方法

ツールの種類:

JavaScriptデベロッパーツール
Rubyのbyebug
PHPのXdebug

コード上でのブレークポイントの設定方法:

JavaScript: debugger;
Ruby: binding.irb

ステップ実行の種類:

・ステップイン:すべての行を1行ずつ実行する
・ステップオーバー:関数の中身には立ち入らず、全体の流れを1行ずつ確認する
・ステップアウト:関数内部の確認が不要になった場合、現在の関数から抜け出す

5. それでも解決できない時は?

目的に対しての原因がわからなければ、問題を回避して別のやり方で目的を達成することも可能!

6. デバッグしやすいコードの書き方

・再代入は控える

定義した変数に他の値を入れること❌
変数名を別のものにして代入すること⭕️
letではなくconstを使うようにすること⭕️
再代入を避けることで、一度のデバッグで二つの変数の中身を同時に確認でき、効率的なデバッグが可能になります。

・スコープは可能な限り狭めること

例えば、if文でtrueの場合のみ使用する変数は、if文の外ではなく中で定義することで、不要にfalseの場合の処理に影響を与えないようにできます。
スコープを狭めることで、コードの可読性が向上し、プログラムのパフォーマンスが改善され、予期せぬ変更のリスクも減ります。

・単一責任の原則を知ること

単一責任とは、クラスや関数などのコードが持つべき責務を一つに限定するというルールです。
例えば、updateProfile()という関数で管理者とユーザー両方のプロフィール更新を扱うと、一見効率的に見えます。しかし、管理者向けに「更新履歴を残す」機能を追加すると、ユーザーの更新機能に影響が出てしまう可能性があります。一つの関数には一つの機能のみを持たせることで、開発時は手間がかかりますが、運用時の不具合を防ぐことができます。

・純粋関数を利用しよう

純粋関数は以下の二つの条件を満たすものです:
1.引数が同じであれば同じ戻り値となる
2.副作用がない

例えば、りんごの計算の関数を考えてみましょう:


def add(a, b)
a + b
end

この関数にa=2, b=3を渡せば、必ず5が返ってきます。しかし、「昨日食べた分も計算に入れる」となると、外部の状態に依存するため純粋関数ではなくなります。

  1. メリットは?
    予測しやすい動作、コードの再利用が容易、テストが簡単、デバッグが簡単。
  2. どんな時に使用する?
    計算やデータ変換、テストをする際、再利用が必要な処理がある際など。
  3. 使用しない場面は?
    外部とのやりとりがある場合、状態を更新する必要がある場合、副作用(関数外部の状態を変更すること)が必要な場合など。
  4. つまり、デバッグや更新時に予期せぬ影響を防ぐため、できる限り純粋関数を使用することが重要です。

・型を意識してコードを書くこと

型を意識するとは、値の種類(数字、文字列、配列など)を理解し、それぞれの型に適した操作を行うことです。
型を意識せずにコードを書くと、実行時にエラーが発生し、問題の発見が遅れる可能性があります。

まとめ

この本を読んで一番ためになったのは、「コードは、デバッグや更新をする際に範囲が大きいコードを使用してしまうと副作用があるため、できる限り範囲の狭いコードを使用すること。」です。
これからも日々学習をし続けて成長していきたいと思います。

15
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?