【初心者向け】エラーを握りつぶすことの問題と対処法

【初心者向け】エラーを握りつぶすことの問題と対処法

今回はプログラミング初学者向けに、エラーを握りつぶすことの問題とエラーハンドリグについて解説します。

javascriptを用いて解説しますが、以下の2点は把握している前提で書いています。

  • jsの基本的な構文
  • try catchの使い方

エラーを握りつぶすとは

エラーを握りつぶすとは、以下のようにでエラーをキャッチしたは良いが、エラーが発生したときの処理を何も書かかないことで、エラーが発生したことを分からなくてしまうことを言います。

try {
  throw new Error('エラーメッセージ')
} catch (error) {
}

例えば、以下のコードを実行すると

const throwError = () => {
	try {
	  throw new Error('エラーメッセージ')
	} catch (error) {
	}
}

const func = () => {
  console.log('start')
  throwError()
  console.log('finish')
}

func()

出力結果はstartとfinishが出力されるだけになります。

start
finish

実際にはstartとfinishの出力の間でエラーが発生していますが、throwError関数でエラーを握りつぶしているためエラーが発生していることに気づくことができません。

エラーを握りつぶすことの問題は、主に2点あります。

  • デバッグが困難になる
  • ユーザー体験が悪い

デバッグが困難になる

具体例で見たように、エラーを握りつぶすと実際にはエラーが発生しているが気付けない状態となるため、システムがなぜ動作しないのか、何が原因で動作していないのかを特定することが難しくなります。

ユーザー体験が悪い

開発者がエラーの原因を把握できないということは、当然ユーザーもエラーの原因を把握することができません。

せめてエラーが発生していることが分かるようなアラートを出せれば良いですが、エラーを握りつぶしている場合、エラーが発生しているかどうかもユーザーに伝えることができなくなります。

対処方法

ログを出力する

開発者がデバッグをしやすいように、エラーのログを出力するようにしましょう。

const throwError = () => {
	try {
	  throw new Error('エラーメッセージ')
	} catch (error) {
	  // エラーのログを出力する
	  console.log(error)
	}
}

const func = () => {
  console.log('start')
  throwError()
  console.log('finish')
}

func()

出力結果

start
Error: エラーメッセージ
finish

ログを出力するようにしたことで、エラーが発生していることに気付けるようになりました。

エラーが発生した箇所で処理を止めたい場合は、throwError関数のcatch内でエラーを投げるようにしましょう。

const throwError = () => {
	try {
	  throw new Error('エラーメッセージ')
	} catch (error) {
	  throw new Error(error.message)
	}
}

const func = () => {
  console.log('start')
  throwError()
  console.log('finish')
}

func()

出力結果

start
Error: エラーメッセージ

ユーザーに通知する

開発者に分かりやすいように、ログを出力するとともに、必要に応じてユーザーにもエラーを確認できるようにしましょう。

const throwError = () => {
	try {
	  throw new Error('エラーメッセージ')
	} catch (error) {
	  throw new Error(error.message)
	}
}

const func = () => {
  try {
    console.log('start')
	  throwError()
	  console.log('finish')
  } catch (error) {
    // アラートを出す
    alert('エラーが発生しました。')
  }
}

func()

これにより、ユーザーもエラーが発生していることが分かるようになり、操作ができないなどの問題があってもエラーが起きていることが原因だと分かります。

今回は簡易的にアラートを出していますが、実際のアプリケーションではエラーの詳細や解決策を示すとよりユーザー体験の向上に繋がります。

気をつけるべきポイント

エラーハンドリングは関数のネストが深くなったり、システムが大規模になってくるとより複雑になっていきます。

例えば、以下のコードを実行すると

const throwError = () => {
	try {
	  throw new Error('エラーメッセージ')
	} catch (error) {
	  throw new Error(error.message)
	}
}

const func = () => {
  try {
    console.log('func start')
    throwError()
	  console.log('func finish')
  } catch (error) {
    console.log(error.message)
  }
 }

const main = () => {
  console.log('main start')
  func()
  console.log('main finish')
}

main()

出力結果は以下のようになります。

main start
func start
エラーメッセージ
main finish

ここでのポイントは「main finish」が出力されていることです。

main関数ではエラーハンドリグを行っていないため、このような挙動になります。

これが期待通りの場合は問題ありませんが、throwErrorのエラーが発生した場合、main関数の処理も止めた場合には問題です。

main関数の処理も止めたい場合、どのように対処するべきでしょうか。

対処方法はいくつかありますが、例えば以下の2点があります。

  • func関数のcatch内でも、エラーを投げるようにする
  • func関数のtry catchをやめる

これらの共通点は、main関数にエラーを伝えていることです。

このように、システムが複雑になってきて階層が深くなると、エラーハンドリグをすべき場所、しなくても良い場所など、エラーを握りつぶさないために、正しくエラーを伝搬する必要がでてきます。

とりあえずtry catchを使用してログを出力すれば良い訳ではないので、エラーを適切に対処できているかは常に気をつけましょう。

Anycloudではプロダクト開発の支援を行っています

プロダクト開発をお考えの方はぜひAnycloudにご相談ください。

まずは相談する

記事を書いた人

そうま

エンジニア

そうま

Anycloudでエンジニアをしています。