プログラムを書いていると問題に遭遇します。問題に遭遇したときはエラーメッセージが問題解決の重要な情報になります。しかし、エラーメッセージがあるだけでは問題解決にはつながりません。問題解決に役立つエラーメッセージとそうでもないエラーメッセージがあります。
ここでは、Rubyでの例をまじえながら問題解決に有用なエラーメッセージを紹介します。ライブラリなど多くの人が使うようなプログラムを作成する場合は参考になるかもしれません。
問題解決への道
問題に遭遇してから問題を解決するまでには以下の順で作業をする必要があります。
-
問題の把握
-
問題の原因の調査
-
原因の解決方法の検討
-
解決方法の実装
役立つエラーメッセージがあると「1. 問題の把握」、「2. 問題の原因の調査」、「3. 原因の解決方法の検討」がはかどります。
問題の値を示す
エラーが発生すれば問題が起こっている事実は把握できます。次にすることは、どのような問題が起こっているかを調査することです。
String#gsubにはいくつかの使い方がありますが、その1つは以下のように正規表現と文字列を引数にする使い方です。
>> "abcde".gsub(/c/, "C")
=> "abCde"
もちろん、違うオブジェクトを渡すとエラーが発生します。
>> "abcde".gsub([:first], [:second])
TypeError: can't convert Array into String
from (irb):2:in `gsub'
from (irb):2
配列を文字列に変換できなかったといっています。しかし、ここでは引数に配列を2つ指定しています。このエラーメッセージでは「配列を文字列に変換できなかった」ことはわかりますが、「どの配列を文字列に変換できなかった」かはわかりません。
正規表現のリテラルでも、正規表現の構文が間違っている場合はエラーが発生します。
>> Regexp.new("(")
RegexpError: premature end of regular expression: /(/
from (irb):3:in `initialize'
from (irb):3:in `new'
from (irb):3
この場合は「正規表現に問題がある」というだけではなく、「どの正規表現に問題がある」かも示しています。
このように、問題を起こしたオブジェクトの情報も示すことで「問題を把握」しやすくなります。エラーメッセージには、問題を起こしたオブジェクトの情報も含めるようにしましょう。
どう悪いのかを示す
問題が把握できたら、どうしてその問題が発生したのか、原因を調べます。多くの場合、エラーメッセージに問題の原因は書かれています。しかし、そうではない場合もあります。できるだけ、エラーメッセージには問題の原因も含めるようにしましょう。
Time.iso8601はISO 8601で定められた文字列のフォーマットをパースし、Timeオブジェクトにします。
>> require 'time'
=> true
>> Time.iso8601("2009-04-10T12:02:54+09:00")
=> Fri Apr 10 03:02:54 UTC 2009
不正なフォーマットの場合はエラーが発生します。
>> Time.iso8601("2009-04-10I12:02:54+09:00")
ArgumentError: invalid date: "2009-04-10I12:02:54+09:00"
from /usr/lib/ruby/1.8/time.rb:376:in `iso8601'
from (irb):6
この例では真ん中あたりの「T」が「I」になっているためフォーマットに適合していません。
もし、「『I』という不正な文字があります」というようなメッセージが入っていると、問題の原因を簡単に把握できるようになります。
エラーメッセージには大雑把な原因だけではなく、できるだけ詳しく原因を書くようにしましょう。
期待を示す
問題の原因がわかったら、その問題を解決する方法を検討します。期待している値がわかると、解決する方法を検討しやすくなります。
String#deleteは1つ以上の引数をとります。1つも引数を与えない場合はエラーが発生します。
>> "abcde".delete("a")
=> "bcde"
>> "abcde".delete
ArgumentError: wrong number of arguments
from (irb):2:in `delete'
from (irb):2
エラーメッセージを見ると「引数の数が違う」ということがわかります。これで「問題の原因」を把握することができます。
しかし、「問題の原因」はわかってもどうすればその問題を解決できるかはわかりません。引数の数を変えればよいということはわかりますが、いくつにすればよいかがわからないのです。
期待している値を示すと、問題を解決しやすくなります。
>> "abcde".gsub
ArgumentError: wrong number of arguments (0 for 2)
from (irb):3:in `gsub'
from (irb):3
このエラーメッセージからはString#gsubが2つの引数を期待していることがわかるので、解決案として「引数を2つ渡す」というアイディアが浮かびます。次にすることは「引数に何を2つ渡すか」を考えることです。
エラーメッセージに「期待していること」を含めると、解決案が浮かびやすくなります。できるだけ、期待していることも含めるようにしましょう。
まとめ
Rubyを例にして問題解決に役立つエラーメッセージについて紹介しました。
問題解決に役立つエラーメッセージの特長は、テストの実行結果にもあてはまります。クリアコードが開発に関わっているテスティングフレームワークではテストの実行結果にこだわっています。
あなたが使っているテスティングフレームワークは問題解決に役立つような情報を提供していますか?