コードやコマンドのエラーはこうやって対処する

# エラー解決できない人が多すぎる問題

　私は、大学は情報系の学科所属ですが、情報系の学科の生徒全員がプログラミング周りのプロフェッショナルな訳ではありませんでした。そして一番問題なのが、技術的なことではなく、自分でエラーを解決できない人が多すぎることです。

　私の周りの友人は比較的優秀でしたが、その友人達でさえ、簡単なエラーで躓いて私に聞いてくることもありました。

　今回は私が考える、エラー解決をするための基本的な道のりを考えました。これらができるようになれば、簡単なエラーで躓いたりすることはなくなるかな、と考えています。

　もしかすると、私なりの考えなのでもっと言うべきこともあるかもしれません。
　また、今回は特定の言語やコマンドの場合ではないので、場合に特化した対処法ではないことをご了承ください。
　それと、説明のために、「なんだこれ」と思われるのようなコードが出てきますが、あくまで説明用なのでコードの方は参考にしないでください。

# エラー解決のための道のり

## Level 1 まずはググれ

　簡単なcのコードを用意しました。

```error1.c
#include <stdio.h>
int main(void) {
    printf(1 + 2);
    return 0;
}
```

　PythonやJavaScriptに慣れている人ならやってしまいがちのエラーですね。`printf`の書式と違います。これをコンパイル、実行をすると私の環境では以下のようなエラーが吐かれました。

```
a.c:3:12: warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'const char *' [-Wint-conversion]
    printf(1 + 2);
           ^~~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/stdio.h:170:36: note: passing argument to parameter here
int      printf(const char * __restrict, ...) __printflike(1, 2);
                                       ^
a.c:3:12: warning: format string is not a string literal (potentially insecure) [-Wformat-security]
    printf(1 + 2);
           ^~~~~
a.c:3:12: note: treat the string as an argument to avoid this
    printf(1 + 2);
           ^
           "%s", 
2 warnings generated.
zsh: segmentation fault  "/Users/hoge/workspace/"error1
```

　エラーを見て慣れている人なら、このエラーを見れば、`printf("%d", 1 + 2);`といった具合にコードを修正できると思います。

　しかし、プログラミング初心者でついうっかり書式を忘れてしまった場合や、全く知らないライブラリのエラーなら、何のことやらさっぱりわかりません。

　ですが、安心してください。誰かがしているミスは、大抵他の誰かもしています。なので、その誰かさんはきっとネットで質問したり、そのミスを見越した説明サイトがネットのどこかに転がったりしているものです。
　なので、まずはネットで調べてみましょう。

**追記**
　コメントで、コードについて@fujitanozomuさんからご指摘をいただきました。~~確かに配列で初期化を行なっていない、そもそも変数で初期化をしているという初心者顔負けのミスを犯していました。申し訳ありません。取り敢えず、それらの修正とそれに伴うエラー文の変更を行いました。
　本来ならエラーの詳細が記事に書いてもいいぐらい短く、調べたら原因をおおよそ特定でき、なおかつコードが簡単な例を出せれば良いのですが、思いつきませんでした。どなたかもっと良い例があればコメント欄に書き込んでください。良い例があれば修正いたします。~~
->私が提示した例よりわかりやすい例をいただいたので、そちらのコードとエラーに差し替えさせていただきました。

　また、エラーを詳細に吐くオプションもあるともコメントいただきました。確かにCにおいて、このような手段は有効であると思います。しかし、本記事ではこのような特定の場合の対処法は扱いませんので、ご容赦ください。詳しくは[頂いたコメント](https://qiita.com/xjam12h/items/082bdf34fa7063af20e4#comment-6bc5c7f85dd509a538b7)をご覧になるか、ご自身で調べてみてください。

## Level 2 エラー文を読め

　エラー解決ができない人はここで躓くことが多いかな、と思います。
　エラー文は短い場合もありますが、場合によってはスクロールしても、どこまでもエラー文が続くことがあります。複雑なプログラムであればある程、エラー文が長くなる可能性は高くなります。しかし、重要な文は意外と少ないもので、エラーの場所を示すために何行も使っていることがほとんどだと思います。

　例えばこういったPythonのコードがあったとします。

```error2.py
import numpy as np

def func1():
    a = np.array([1,2,3],[4,5,6])
    return a

def func2():
    return func1()

arr = func2()

```

　これを実行すると、

```
Traceback (most recent call last):
  File "/Users/hoge/workspace/error2.py", line 10, in <module>
    arr = func2()
  File "/Users/hoge/workspace/error2.py", line 8, in func2
    return func1()
  File "/Users/hoge/workspace/error2.py", line 4, in func1
    a = np.array([1,2,3],[4,5,6])
TypeError: Field elements must be 2- or 3-tuples, got '4'
```

という感じで怒られます。

　どんなエラーなのかという点で重要なのは一番下の`TypeError`のとこで、他はエラーの場所を示して長くなっています。

　あくまでこれは一例なので、こんなに短ければラッキーなのですが、もっと長い方が多いです。短ければ最悪エラー文を対象に検索しても良いのですが、長ければ検索キーワードの制限に達してしまい、検索できません。なので、どこにどういったことが書いてあるのかを把握することが重要になってきます。

　英語が読むのが辛い、しんどい、といった方は、翻訳にかけましょう。これだけで多くの人にとって、格段にエラーを読むのが楽になります。その上でどこが重要な部分かを見極めましょう。そして、エラーを読んでもわからない、解決できない場合に検索をかけます。

## Level 3 検索の仕方を考えろ

　検索する時に何も考えずにいると、一生求めている答えに辿り着けない場合があります。

　例えばこういったコマンドがあったとします。

```sh
$ ls -h
```

　エラーではないですが、このコマンドの意味がわからなかったとします。このとき、意外とやってしまっている人が多いのが、意味を知ろうとこのコマンドをそのまま検索してしまうことです。

　するとどうでしょう、検索結果にはレクサスのことしか出てきません。`ls`だけで検索しても似たような結果になるのですが、この場合は検索の仕方に問題があります。

　検索エンジン上で単語の最初に「-(ハイフン)」をつけて検索をすると、その単語が出ないように検索してしまいます。なので、検索の仕方を工夫する必要があります。
今回の場合だと、「ls "-h"」とダブルクォーテーションで囲って検索することで絶対「-h」を含むように検索したり、「ls h オプション」などと検索する必要があります。

　検索力には単語のチョイスだけでなく、こういった検索エンジンの特性を理解することも重要な訳ですね。

**追記**

　こちらも@fujitanozomuさんからコメントで頂いた通り、`man ls`や`ls --help`でコマンドの詳細を知ることができます。
　どちらかというとここで書いた対処法は、例えばですが、GitHubなどに上がっている他人のコードを実行し、エラーが出て、似たような現象が他の人でも起こっていないか、を調べるときに有効です。打ったコマンドと、エラー文を一緒に調べていただくと、良いかと思います。
　使い方云々は上記の通りに、使い方を見るコマンドを打ったり、公式サイトを見ていただいた方が早いかと思います。あくまでここで記したものは、調べ方に気をつけて頂くための例のつもりでした。
　私の言葉が足りず申し訳ありません。

## Level 4 直接的な解決法だけじゃなく、原因を考えろ

　人はすぐに楽をしたがるので、調べるときに解決法をまず探そうとします(偏見)。
しかし、それだけで解決できるとは限りません。同じエラーは見つかるのに、ライブラリが違ったり、環境が違ったりします。そうなると、自分が欲している解決法とは違ったものが提示されていることがあります。

　これは実際にあった話なのですが、ある友人がMacOSで使用できるかわからないライブラリを入れてみたが動かなかったので助けを求めてきたことがありました。結論から言うとそのライブラリはMacで使われるApple M1チップ(arm64)での使用を想定されておらず、Intelのチップ(x84_64)で使用する必要がありました。
　私も一瞬諦めかけたのですが、ふと「じゃあ、M1チップでx84_64の環境を作ることはできないのか」と思い、調べてみると、Rosettaを使用することで可能だということわかりました。そして、実際に友人が動かしたかったライブラリもRosettaを使用することで動きました。

　何が言いたいのかというと、「**なぜそのエラーが起こっているのかを考えることが如何に重要か**」ということです。
　解決法を直接調べるのも良いですが、なぜそれで解決するのかがわかっていれば、次に似たようなエラーが起こったときの対処も考えるだけで解決できるかもしれませんし、上記で述べた通り、解決法が直接出てくるとも限りません。
　なので、脳死で検索するマシーンにならずに、思考することも忘れないでください。

　また、エラーの内容の原因を調べるというのは、問題がどこにあるのかを調べるということでもあります。ライブラリの問題なのか、環境の問題なのか、はたまた文法の問題なのか、ということも考えましょう。
　どこに問題があるかわからずに調べていると、文法の問題なのに、ライブラリの解決法が載っているページを調べても出てこないことがあったり、ライブラリが使用している別のライブラリのバージョンが違うことが原因なのにそれに気付かずにライブラリの公式ページを眺めているだけになる、といったことが起こり得ます。
　それでも解決法に辿り着くかもしれませんが、きっと多くの時間を浪費してしまうことでしょう。
きちんと原因を考えることで、時間の節約にもなると思えば、考えることの労力も大したことない、と思えるのではないでしょうか?

## Level 5 それでもわからなければ質問をしろ

　ここまできて、それでもわからない場合は質問をしましょう。
　質問をすることは難しいことではありませんが、何も努力せずに質問すべきではない、という点で質問するという対処法をLevel 5に位置付けました。

　Level 1のただ検索しただけ、または自分では何もせずにエラーが出た段階で誰かに聞きにいってはいませんか?
　それでは質問する人のためにもなりませんし、質問された相手はこれまで話してきた内容のことをする必要があるかもしれません。それは質問された側からすると時間の無駄です。
　なので質問する側は最低限、現状や環境、試したことくらいは伝えましょう。そしてできれば、原因と思われる箇所の特定や自分の解釈を伝えることも行いましょう。そうすることで質問する側が努力したことも伝わりますし、解決に要する時間も短縮され、必要以上に相手の時間を浪費することもありません。
　知り合いに質問するなら円滑な関係のために、ネットで質問するなら質の良い解決法を残すために、質問をする際には質問の仕方にも気をつけましょう。

# 最後に

　まとめると、基本的に大事なことは二点です。「検索すること」と「きちんと考えること」です。それさえできれば少なくとも、全く何もわからない、という事態は避けられると思います。

　上記に書いた以外でも、デバッグツールを用いたり、オプションでより詳しい情報を表示したり、経験で何とかしたりと解決法は色々ありますが、どの言語やライブラリでも言えるようなことを記述しました。

　Levelは難易度を表したつもりでしたが、Level 5の質問するというのは最終手段というか、自分にできることを全てやったという意味で一番高いLevelにしましたので、難易度的にはちょっと微妙なLevel付けだったかもしれませんね。

　長々と拙い文章になってしまったと自分でも思いますが、この文章を読むことによって一人でも多くの役に立てれば幸いです。