はじめに
この記事は以前執筆した『プログラミング初心者歓迎!「エラーが出ました。どうすればいいですか?」から卒業するための基本と極意(解説動画付き)』という記事の派生記事です。
もともと上記の記事に追記するつもりで書いていたのですが、長くなったので独立した新しい記事として公開します。
本記事は上記の元記事と同様に、「エラーが出ました。どうすればいいですか?」と右往左往してしまう初心者プログラマさんのヒントになるような考え方を提供するのが目的です。
それでは以下が本編です。
「ボタンをクリック」から「画面に何か表示」までの長く複雑な旅
たとえば、あなたが何かプログラムを作っているとき、「画面上のボタンをクリックしたのに全く何も反応がない」という問題に遭遇したとします。
このとき「あれ、なんで何も起きないの??誰か助けてー!!」と助けを求める前に、ちゃんと自分が頭の中で処理の流れがイメージできているのか確認しましょう。
ボタンをクリックしてから画面上で何かデータが表示されるまで、正常なRailsアプリケーションのAjax処理であればこんな順番で処理が行われるかもしれません。
- ブラウザ上のボタンをクリックする
- JavaScriptのonclickイベントが動作する
- onclickイベント内のJavaScriptがWebサーバーにリクエストを投げる
- Wifiを経由して自宅やオフィスのWifiルーターにリクエストが届く
- WifiルーターからLANケーブルを通ってインターネットの世界にリクエストが飛んでいく
- クラウド上のWebサーバーがリクエストを受け取る
- Railsアプリケーションがリクエストを受け取り、どのコントローラに処理を渡すか決定する(routes.rbのルーティング)
- コントローラがリクエストを受け取り、適切なアクションを実行する
- コントローラのアクション内でモデルの処理を呼び出す
- モデルはデータベースにクエリを投げる
- データベースはモデルから要求されたクエリに従って適切なデータを返却する
- モデルはデータベースからデータを受け取り、コントローラに渡す
- コントローラはモデルからデータを受け取り、Viewにデータを渡す
- Viewでは受け取ったデータをJSONとしてレンダリングする
- コントローラからWifiルーターまで、さっきとは逆の順でJSONデータが返ってくる
- Wifi経由でブラウザまでJSONデータが返ってくる
- JavaScriptのコールバック関数が返ってきたJSONデータを受け取る
- コールバック関数内でJSONデータを適切に処理する
- JSONデータの内容がブラウザ上に反映される
- ゴール!!🎊
2020.8.31追記
上に書いた「長く複雑な旅」とよく似た話を説明しているツイートがあったので、引用させてもらいます。
URLをブラウザに入れてから戻るまでの仕組み。めっちゃわかりやすい。 pic.twitter.com/gKhSjoGKxa
— うめ⚡️ITエンジニア🔛London🇬🇧 (@beConjuror) August 30, 2020
また、こちらの記事でもより詳しく「長く複雑な旅」が解説されています。
https://github.com/tetz-akaneya/what-happens-when-JA
このレポジトリは昔からある「google.comとブラウザのアドレスバーに打ちこんでEnterを押すとき一体何が起きているのか?」という問いに答えるのものです。
一般的な回答とは違い、全ての部分についてできる限り深く答えます。
すべてのプログラムは巨大なピタゴラ装置である!?
僕はプログラムがこんなふうに動いていることをイメージすると、頭の中で巨大なピタゴラ装置の映像が思い浮かびます(ピタゴラ装置をご存じない方はググってみてください)。
Image: MASAHIKO SATO | TOPICS OF TOPICS :: ピタゴラ装置の意志
ボタンのクリックはピタゴラ装置で一番最初にボールがコロコロと転がり始めるシーンです。
ブラウザに何かデータが表示される一番最後のイベントは「ピタゴラスイッチ」と書かれた小さな旗がぴょこんと立ち上がるシーンです。
その間、無数の複雑な装置を経由しながら、ボールはどんどん別の物体にバトンタッチしながら、次から次へと処理が進められていきます。
ですが、どこか一箇所でもおかしな部分があると、ピタゴラ装置の動きは途中で止まってしまいます。
もちろん「ピタゴラスイッチ」と書かれた小さな旗は立ち上がりません。
「ボタンをクリックしても全く何も反応がない」というのはまさに、ピタゴラ装置がおかしくなって途中で動きが止まってしまった状態そのものです。
プログラムとピタゴラ装置の大きな違い
ただし、プログラムとピタゴラ装置では大きく異なる点が2つあります。
プログラムは一瞬で完了する
ひとつは、プログラムは複雑な処理も一瞬で処理が完了してしまう点です。
ピタゴラ装置は何十秒もかけてゆっくり動きますが、正常なプログラムはコンマ数秒で完了します(中には時間のかかるプログラムありますが、それは別として)。
そのため、ボタンをクリックしてから画面に表示されるまでの長くて複雑な過程がイメージしづらくなります。
プログラムの動きは目に見えづらい
そして、もう一つの違いはプログラムの動きは目に見えづらい点です。
ピタゴラ装置であれば、最初から最後まで人間が目で動きを追いかけることができます。
途中で止まってしまったときは「あ、止まった」「うまく動かなかったのはこの部分か」ということが一見して分かります。
しかし、プログラムの処理や必要なデータが動いているのはコンピュータの中であったり、Wifi信号の中だったり、ネットワーク回線の中だったりして、そう簡単に視覚化することができません。
先ほどの例であれば、人間の目で見て明らかなのは「ボタンをクリックした」「画面に何か表示された」ということぐらいです。
こうした違いがあるため、プログラミング初心者の人はピタゴラ装置の原因調査と違って、プログラムがうまく動かない理由が推測できず、「あれ、動かない!誰か助けてー!!」となるんだと思います。
「あれ、動かない!誰か助けてー!!」とあわてないために
では、こうした問題にはどう対処すればいいでしょうか?
「あれ、動かない!誰か助けてー!!」とあわてないようになるためには、以下の3つの考え方やテクニックを身につける必要があります。
- プログラムが動くまでの長くて複雑な道のりをイメージしよう
- プログラムの動きを可視化するテクニックを身につけよう
- 仮説と検証を繰り返して隠れたバグをどんどん追い詰めよう
それぞれについて以下で詳しく説明します。
プログラムが動くまでの長くて複雑な道のりをイメージしよう
まず、一番大事なことは「ボタンをクリックする」と「画面に何か表示される」の間にある、長くて複雑な道のりをイメージできるようになることです。
あなたは「ボタンをクリックする」と「画面に何か表示される」の間で何が行われているのか、どれだけ細かく自分の言葉で語ることができますか?(何も見ずに、何も調べずに!)
ほとんど何も口に出せないのであれば、明らかに勉強不足、プログラミングの基礎体力不足です。
Webアプリケーションがいったいどんな技術要素で構成されているのか、そしてその技術がそれぞれどんなものなのかを理解するところから始めましょう。
プログラムの動きを可視化するテクニックを身につけよう
次に大事なことは、プログラムの動きを可視化するテクニックを身につけることです。
先ほど、「プログラムの動きは目に見えづらい」と説明しました。
僕がここで「見えない」ではなく、「見えづらい」と表現した点に注目してください。
プログラミングをまったく知らない素人さんには何も「見えない」かもしれませんが、われわれ技術者は専門知識や専門的なテクニックを駆使することで、プログラムというピタゴラ装置の動きを可視化することができます。
具体的には、たとえば以下のようなテクニックが使えます。
- ブラウザの開発者ツールを使う
- サーバーが出力するログを確認する(またはデバッグ用にログの出力を追加する)
- デバッガを使ってブレイクポイントで処理を止めたり、ステップ実行したりする
こうした引き出しをどれだけたくさん持っているか、どれだけ上手に使いこなせるかが初心者プログラマと熟練プログラマの大きな違いです。
上記のようなツールやテクニックをまったく使っていないという場合は、まずそれらを使いこなせるような勉強をしましょう。
ただ、このあたりのテクニックは独学で習得するのが少し難しかったりします(とっかかりになる知識がないと、どんなツールやテクニックがあってどう使えるかというイメージすらわかないため)。
ですので、できれば先輩プログラマにペアプログラミングならぬ、ペアデバッグをお願いするのがいいと思います。
仮説と検証を繰り返して隠れたバグをどんどん追い詰めよう
「プログラムが動くまでの長くて複雑な道のりのイメージ」と「プログラムの動きを可視化するテクニック」が身に付いていれば、不具合解決までの距離がぐっと縮まります。
あとは仮説と検証を繰り返して隠れたバグを追い詰めるだけです。
デバッグにおける仮説と検証とは、次のような手順を踏むことを指します。
- 「おかしいのは〇〇の処理が原因でないか」と仮説を立てる
- 「〇〇が正しく動くのであれば、△△であることが確認できるはずだ」と、仮説を検証する方法を考える
- 実際に△△になることを検証する(ここが可視化テクニックの出番!)
- (予想通り△△であることが確認できた場合)〇〇の処理には問題がなく、原因は別の部分にあるので次の仮説を立てる
- (△△にならなかった場合)〇〇の処理が原因である可能性が高いので、〇〇の処理を重点的に調査する
もう少し具体的な例を挙げるなら次のような感じです。
- 「おかしいのはJavaScriptのクリックイベントが正しく設定されていないのが原因ではないか」と仮説を立てる
- 「クリックイベントが正しく設定されているなら、ボタンをクリックしたタイミングでこのブレークポイントで停止するはずだ」と考える
- ブラウザの開発者ツールを使って実際にブレークポイントを設定し、画面上のボタンをクリックする(検証)
- (予想通り停止した場合)クリックイベントには問題がないので、次の仮説を立てる
- (停止しなかった場合)クリックイベントが正しく設定されていないので、クリックイベント周りを重点的に調査する
こんなふうに調査していくと、たとえば「あ、クリックイベントを設定したつもりだったけど、よく見たら指定したCSSのclass名をtypoしてるやん!!」という原因に気づけたりするわけです。
「どこがおかしいのかまったくわからん」という状態から、仮説と検証を繰り返して「このへんがなんか怪しい → その中でも特にこのへんが臭うぞ? → もしかして・・・あーっ、原因はお前かー!!」と、徐々に犯人を追い詰めていく感覚を楽しみましょう😎
まとめ
というわけで本記事では、「あれ、動かない!誰か助けてー!!」と困っているプログラミング初心者さんのために、ピタゴラ装置のたとえを使いながら、効果的なデバッグの方法を説明してみました。
プログラムは巨大なピタゴラ装置である、というイメージがなんとなく伝わったでしょうか?
もしうまく動かないプログラムに遭遇したときは、頭の中で自分のことを「ピタゴラ装置を修理しに来たお店のスタッフ」だと思ってください。
デバッグは壊れたピタゴラ装置の修理です。
「あれー、ボールが止まっちゃったのはどこかな〜?ここかな〜?こっちかな〜?それともここかな〜??」と、ボールの流れを追いながら、また、どこまで動いてどこから止まっているのか自分の目で確認しながら、壊れたピタゴラ装置を直していきましょう。
さあ、みなさんも一流の修理スタッフ・・・じゃない、一流のプログラマを目指して、デバッグに関するいろんな知識やテクニックを身につけていきましょう!
あわせて読みたい
デバッグが苦手な初心者プログラマさんは冒頭で紹介したこちらの記事も一緒にご覧ください!
プログラミング初心者歓迎!「エラーが出ました。どうすればいいですか?」から卒業するための基本と極意(解説動画付き)
おまけ: デバッグじゃなくても「ピタゴラ装置」のたとえは有効?
プログラムはピタゴラ装置だと考えると、「一気に全部作ってから動かす」よりも「ちょっと作っては動かす」を繰り返した方が良い、という理由も理解しやすいかもしれない。だってみんなも、最初は「ボールが転がって小さなバケツにちゃんと落ちること」から確認したくなるよね。(ね!?)
— Junichi Ito (伊藤淳一) (@jnchito) December 26, 2018