超大事な考え方「問題の切り分け」について

今回は、とても大事な考え方「問題の切り分け」について解説していきます。

問題の切り分けは、

「何か問題が起きたときに、どこが原因で問題が起きているか」

を突き止めるためのものです。

 

この切り分けがうまくできないと、しらみ潰しに確認する必要があるため、問題を特定するまでに、かなりの時間がかかってしまいます。

逆に、うまく使えるようになると以下のような状態になります。

問題の切り分けがうまく使えると
  1. 問題の特定までにかかる時間が短くなる
  2. 今まで見たことのないバグを見ても、恐れずに調査を進められる
  3. コーディングスピードが上がる

    いいこと尽くしですね笑

    では、イメージや具体例を交えながら、「問題の切り分け」について詳しく解説していきますね。

    問題の切り分けのイメージ

    まずは、問題の切り分けができている場合と、できていない場合のイメージを共有していきます。

    問題の切り分けができていない場合

    できていない場合、以下のような手順で問題を解決しようとします。

    1. 過去の経験から推測して問題を1発で当てようとする
    2. 原因として思いついたものを順番に試してみる
    3. アイデアが思いつかない場合、手が打てなくなる

    1と2については、経験則から出した方が速いものもあるので絶対ダメ!というわけではないのですが、一番問題なのは3です。

    図にするとこんな感じ。

    1や2で思いついたものが青丸です。正しい問題の原因である赤丸と一致するまで、膨大にある選択肢を試していくことになります。

    手持ちのアイデア(青丸)がなくなった時点で諦めるしかなくなってしまいますし、ある意味当てずっぽうなので、見つけるのにも時間がかかります。

    問題の切り分けができている場合

    では、問題の切り分けができている場合はというと、

    1. 問題の原因が潜んでいると考えられる範囲をいくつかに分ける
    2. 分けた範囲に問題の原因が「ないこと」を確認して原因がある領域を狭める
    3. 1と2を繰り返して問題を突き止める

     

    図にするとこんな感じ。

    図の ①, ②, ③ といったように、原因が潜んでいるだろう箇所を想定します。

    で、原因が潜んでいるだろう問題の原因が①にも③にもなくて、②の領域にあることがわかったとします。

     

    このように、問題の原因がどこに潜んでいるかを絞り込むことで、

    珍獣
    少なくとも原因は②のどこかだから、この範囲を探せば良さそうだ

     

    となったほうが、はるかに効率がいいですし、見たことのないような問題であっても、さらに細かく問題を切り分けていけばいずれ原因がはっきり見えてきます。

    見たことのないエラーであっても、怖がらずに1つ1つ着実に進めていけるので、精神的にも安心できますね!

     

    ねこくん
    言いたいことはわかったけど、それって具体的にどうやればいいの...?

     

    という声が聞こえてきそうですね。次は具体例を交えて説明していきます。

     

    問題の切り分け方

    例1. お問い合わせ「〇〇の新規申し込みができません」

    とあるユーザーさん
    貴社のサービスの〇〇の新規登録をしようとしたのですが、新規登録のボタンを押すとなぜか真っ白になってしまい。。どうすればいいでしょうか?

     

    ある日、上記のような問い合わせがあり、あなたがその原因調査を依頼されました。

    原因の調査を行い、問い合わせの回答を準備したり、必要であればバグの修正をすることになったのですが、さて、どこから見ていったらいいでしょうか?

    今回は「問題の切り分け」の例なので、実際の業務とは少し異なりますが、かなり丁寧めに切り分け作業を行なっていきましょう。

    問題は大きく分けてどこにあるのか

    Web サービスの問題の原因を探るとき、大きく分けると3つの領域に分けることができます。

    1. インフラのどこかに問題がある
    2. サーバーサイドのプログラムのどこかに問題がある
    3. クライアントサイドのプログラムのどこかに問題がある

     

    インフラとは?

    Webアプリが正しく動くには、Webアプリを動かすための環境が整っている必要があります。

    • その Web アプリとデータベースの接続ができているか
    • ユーザーが Web アプリにアクセスしようとしたときに、うまくデータを返すための設定ができているか

    といったもので、「Webアプリ側のPCの環境設定」と言い換えられます。

    図にするとこんな感じですね。

    ※ Web サーバーのアプリケーションの例が nginx で、これがユーザーにデータを返してくれる。

     

    インフラの設定に問題がある場合、「アプリケーション全体が止まってしまう」可能性がありますし、Web アプリにアクセスしようとしても一切反応しない状況になります。

     

    今回の問い合わせでは、

    新規登録のボタンを押すとなぜか真っ白になってしまい。。

    という内容であり、他のページでは問題は起きていなそうなので

    珍獣
    たぶん、インフラの設定は特に問題がなさそうだな

     

    という判断をすることができます。

    サーバーサイドプログラムとは?

    サーバーサイドプログラムは、

    1. ユーザーのデバイスから送られた命令(リクエスト)を受け取り
    2. 送られた命令にしたがって何かしらの処理を行い
    3. ユーザーにデータを返す(レスポンス)

    ためのプログラムです。

    図にするとこんな感じ。

    問い合わせをいただいたのと同じ手順で、エラーを起こしてみたところ、「サーバーの処理に問題がある」エラーが返っていることがわかりました。

    サーバーの処理に問題があるエラーを 500 エラーと言います。これは HTTP ステータスコードという規約で、どんな状態のときにどんな番号のエラーを返すのかが決まっているので、何番のエラーなのかを見ることで、どんなエラーなのかのヒントをつかむことができます。

    こうして、根本的な問題は、

    「新規登録をするときのサーバーサイドプログラムのどこか」 にあることがわかりました。

    こうして、次は上記プログラムの中のどこに問題があるのかを詳しく探っていけばいい、ということになります。

    クライアントサイドプログラムとは?

    クライアントサイドは、「ユーザーが端末で見るための画面」を表示させるためのプログラムです。Web アプリでは、HTML, CSS, JavaScript などの言語で作られます。

    図にするとこう。

    あくまでも、画面を表示させるための情報を返すのは、Webアプリですが、それを受け取って解釈したうえで表示するのは各端末になります。

     

    さて先ほど、致命的な問題はサーバーサイドプログラムにあることがわかりました。

    ただ、「新規登録ボタンを押して、エラーしたタイミングで画面が真っ白になる」というのは、ユーザーは困惑してしまいますよね。

    エラーするにしても、せめて「どうしてエラーしてしまったのか」をユーザーが知ることができれば、比較的問い合わせもしやすくなるでしょう。

    (やや雑ですが)こんな感じで。

    なので、プラスアルファの習性として「500 エラーが出たときに適切なエラーメッセージを表示するように修正する」といった対応を追加することができます。

    まとめ
    • Webアプリで問題が起きたときは、大きく「インフラ、サーバーサイドプログラム、クライアントサイドプログラム」の3つにわけて考えよう
    • 具体的にどこの範囲に問題があるのかがわかったら、さらに深掘りして問題を切り分けていこう

    例2. 設定が必要なプログラムを書き、途中でエラーした

    「問題の切り分け」は、プログラムを書いているときにも使うことができます。というか常に使います。

    例えば、動かすためにいくつかの設定が必要なプログラムを書いていて、それを実行したとしましょう。

    で、そのプログラムの途中でエラーが発生しました。

    大事なのは、「エラーが発生した行より前は、少なくともエラーせずに動いている」 ということです。

    このコードを動かすためには

    1. ファイルの読み込みが正しく行われている
    2. 実行するための設定が適切に行われている

     

    といった、前提条件があり、それらをクリアしてはじめてプログラムが動きます。

    なので、上記ファイルの途中でエラーしたという情報から

    珍獣
    よしよし、実行するための設定は正しくできたな

     

    と解釈できるのです。

    「何ができていて、何ができていないかを切り分けて判断していくこと」が超重要なんです。

     

    あとは、実際にエラーした行を確認し、具体的な問題を探っていけば問題なさそうです。

    Ruby であれば、Error した行の 1 つ前の行に、デバッグコード(`binding.pry` など)を挟んで、具体的にどんなエラーなのかをみていけば OK ですね。

    まとめ
    • 何ができていて、何ができていないかを切り分け、判断していくのが大事!
    • 具体的なエラーは、エラーが発生したところを詳しく見ていけば OK!

    最後

    「問題の切り分け」は、「何か問題が起きたときに、どこが原因で問題が起きているか」を突き止めるためのものです。

    「何ができていて何ができていないのか」の判断を繰り返すことで

    問題の切り分けがうまく使えると
    1. 問題の特定までにかかる時間が短くなる
    2. 今まで見たことのないバグを見ても、恐れずに調査を進められる
    3. コーディングスピードが上がる

    これらのメリットがあるのがわかったのではないでしょうか?

    あまり大々的に扱われる内容ではありませんが、超重要なので普段から意識するようにしていきましょう!

     

    また、本記事は、現場で活躍できるWeb系プログラマー を育成するための教材 Take off Rails の教材のひとつを公開しているものになります。

    もし内容が良かったとお思いでしたら、ぜひ Twitter のフォローLINE@ の登録 をお願いします!