第13講: 映画『プレデター』と「どこが変わったかわかる?」に学ぶバグの潰し方。

バグ潰しの最重要な点は、原因箇所を発見することです。
これができれば、もう半分以上解決です。原因箇所を発見するコツは、映画『プレデター』が教えてくれたように、「可視化して、さらに二分探索法で探すこと」です。
今回のエンジニアジョークで笑えれば、バッチリ合格です!

***

こんにちは。
ゲームが下手くそな、黒田道哉です。

ポケ●ン緑の四天王が、全っ然クリアできなかったんですけど、
近所の5つ上のお兄ちゃんに渡したら、速攻でクリアしてくれました。

一番美味しいところを他人に譲るという。笑

なんていうか、こういうのを、「人を輝かせることができる」って言うんですかね?笑

 

バグ – Bug –

これはプログラマーの天敵です。

かなりやっかいです。
(ポケモンにもバグってありましたよね!仕様って気もしますが!)

 

バグというのは、コード上のミスのことです。

 

誤字・脱字とかならまだ良いんですよ。

なぜなら、見ればわかるんで。
(Ctrl + F の方の)検索をうまく使えば、バグの原因箇所がスグ特定できますから。

こういうのは、バグというよりエラーといいます。

 

本当のバグは、「論理的な整合性が取れておらず、起こる問題」です。

すみません、キモチワルイ言葉を使ってしまって。w
…イメージしにくいですよね。

1=2の証明を否定できるか?

バグがあるってのは、たとえば…

1=2の証明

ってご存知ですか?

これです。

b = a

とする。
この両辺に a を足すと

a + b = 2a

両辺から 2b を引くと

a – b = 2a – 2b

(a – b) = 2(a – b)

両辺を (a – b) で割ると

1 = 2

 

はい。

なんと!!

1=2なんです!!!

 

…笑

もちろん、間違ってます。

でも、どこが間違ってるかわかりますか?

有名なんで、間違いポイントをご存じの方もおられると思います。

初見の場合は、丁寧に読まないと間違ってる場所に気づけません。

 

ちなみに、1=2の証明はどこがダメか?

最後の一手、両辺( a – b )で割るところが、ダメです。
なぜかと言うと、最初に b = a と言ってることから、a – b = 0 ですね。
両辺をa – b つまり 0で割るのはルール違反(どんな数字も、無限大になって一致してしまう)なので、ダメなんです。

b = a

とする。(つまり、a – b = 0ということ)
この両辺に a を足すと

a + b = 2a

両辺から 2b を引くと

a – b = 2a – 2b

(a – b) = 2(a – b)

両辺を (a – b) で割ると(両辺を0で割ってる。ダメ。)

1 = 2

 

これが「論理的整合性が取れていないところを探す」ということです。

一見間違ってなさそうなところから、マズいところを探すんです。
これがバグを探す作業です。
脳に負荷がかかりますよねぇ。

これが、プログラミングにつきものなんです。
あなたも、これからそんな作業をするのかと思うとうんざりですか?

でも、大丈夫です!

バグへの対処法をお教えしちゃいます!
この講座を読んでて良かったですね!

プログラマーの命綱です。
これさえ知ってれば、バグもおそるるに足らず!!!

いきますよぉ〜!

バグの倒し方はプレデターの倒し方と同じ

バグのややこしい点は、目に見えないところです。
であれば、目に見えるようにしてしまえばいいんです。

 

 

シュワちゃん主演の映画『プレデター』で、そんなセリフがありませんでしたか?
ネタバレになっちゃうんですけど…
(まあこういうのはどうせ人間が勝つってわかってるようなもんだし良いですよね。笑)

 

プレデターという、透明で見えないが人間たちを襲ってきます。
見えないから、「チーム人間」はずっとやられっぱなしです。

そりゃそうですね。どっから来るのかわからないですからね。
勝ち目がない!!

苦戦するんですけど、あるとき気づくんですね。

やつら、血が出るぞ!?

 

無敵だと思っていたプレデターには、血が流れているようです。

そこでシュワちゃんは名言を放ちます。

血が流れる=生きている=殺せる

というサイコパス的論理ですね。笑

 

そしてまた、血が流れていることから、
「じゃあひとまず、血を出させてしまおう。
そうすれば、見えるようになるから戦える!」とも気づきます。

そして、最後にはやっつける!

という映画です。

 

 

見えぬなら 可視化してまえ プレデター

 

 

そんなところでしょうか。

 

 

見えないのがイヤなのであれば、見えるようにすれば良い。
バグも同じです。

どうやってバグを可視化するか?

具体的には、
変数のデータを表示する関数(大体print関数とかprintf関数です)を小刻みに入れることで

 

各地点で、データのチェックポイントをつくる

 

ようにします。

例えば、

関数A

関数B

関数C

関数D

というコードがあったとしましょう。

 

バグを可視化するために、
関数に入る前後に
セーブポイントを細かく用意するんです。

 

変数xを表示

関数A

変数xを表示

関数B

変数xを表示

関数C

変数xを表示

関数D

変数xを表示

 

こんな感じです。
高速道路の料金所みたいなイメージですね。
もしくは、RPGで細かくセーブしていく感じ。

こうすることで、

どのタイミングで変数がおかしくなっているのか?

を、ことあるごとに実際に、変数を見ていくわけです。

 

 

変数xを表示 (※ここは思い通り)

関数A

変数xを表示 (※ここは思い通り)

関数B

変数xを表示 (※ここは思い通り)

関数C

変数xを表示 (※ここからなんか変)

関数D

変数xを表示 (※そのせいで、ここも変)

 

 

と言うふうに、チェックしていけば、

「関数Cが問題や」

というように問題箇所を絞ることができます。

 

そしてその関数の内部でも同じように見ていき、

「あ、ここの操作がおかしいわ。」

ということに気がつけるようになります。
これがバグの基本的な探し方です。

 

これだけでも十分、バグは見つけられます。

 

しかし!!!

 

 


ここからがエンジニア
らしい発想なんですねぇ〜!

もっとラクに見つけるズル賢い方法〜二分探索〜

更に効率よくバグの原因箇所にたどり着く方法ってのがあります。

だって、いちいちことあるごとにprintf()を刻んでいくの、めんどくさいですよね。

しかも、バグが見つかった後、それを消していくのも面倒です。
(デバッグモードで動かして、ブレイクポイントでチェックするという技ができるとベター。)

 

そもそもどこからチェックしていけばいいかわからない!などの問題もあります。

 

もっとラクしましょう。それがエンジニアってもんですよ!
そんなときに使う発想(アルゴリズム)が、

 

「二分探索法(にぶんたんさくほう)」

 

です。

その名の通り、一言で言うと、

対象エリアの半分だけをサーチしていく方法」です。

大丈夫!簡単です!

 

数値あてゲーム」でご覧に入れましょう。

たとえば、
あなたが、1〜20の数値で好きな数値を選びます。
(実際に今、選んでみてから、読み進めてみてください)

 

その数値がバグの箇所ってことにしましょう。

そしてその数値を私が当てます。

いや、当てるというより、絞り込みます

 

まず、私はあなたにこう訊きます。


「その数値(バグ)は1〜10の間にある?」・・・(★)

これであなたがどう答えても、対象エリアを半分に絞れるわけです。

 

もし()に対してあなたが

「うん。(1〜10の間にあるよ)」

といえば、次は私が

その数値は1〜5の間にある?

と、更に半分に絞って訊きます。
そこであなたが

「いいえ。(6〜10の間にあるよ)」

と答えれば、次は私が

「その数値は、6〜8の間にある?」

と更に半分に絞るわけです。
これを続けると必ず数値を当てられます。

 

もし()に対してあなたが

「いいえ。(11〜20の間にあるよ。)」

と答えても同じことです。
次は私が

その数値は11〜15の間にある?

と、更に半分に絞って訊きます。

 

こうやって絞っていけば、
必ず、答え(バグ)にたどり着けますよね。
(じわじわと確実に追い詰められてる感あったんじゃないですか?w)

しかも、
数字を当てる側は、
みるべき箇所を半分捨てられるんですから、労力も半分になっていきます。

可視化と組み合わせると最強

じゃあこれをプログラムでどうやって実装するのか?というと、

関数A

関数B

変数xを表示

関数C

関数D

というように、
ざっくり半分に分けて、
片方の半分でバグってるかどうかを、printf()で見極めます。

関数A

関数B

変数xを表示 (※ここは思い通り)

関数C

関数D

となるとしたら、次は関数C, Dが怪しいわけです。
なのでCとDの間でチェックします。

関数A

関数B

関数C

変数xを表示 (※ここで変)

関数D

こうすれば、関数Cがバグってることがわかります。

さっきは「変数xを表示」を5回もやりましたが、

今回はたった2回で済みました。

労力も減ってますね。

こんな風に、

まず半分でバグチェック
バグってなければもう片方のほうを、二分して…
バグっていれば、そのエリアをさらに二分して…

と調べていく。

これが、「二分探索法」です。

な〜んだ、簡単!

 

ということで、

バグは、可視化して探す。
探すときは、二分探索する。

という超ウルトラスペシャルハイパー重要なお話でした!

(こういうのは、アルゴリズムの勉強を通して学習します)

 

P.S.

ちなみにこの一連のバグ探しの方法を、
私は「printf作戦」と呼んでいます。笑
(ダッサーw)

 

次回予告

次回は 映画『メメント』に学ぶ、コーディングの心得 をご紹介します。

コードで大切なのは、コードじゃない部分にあります…。

第14講: 映画『メメント』に学ぶコーディングでかなり重要なこと
プログラミングで意外に重要なことを、クリストファーノーラン監督の映画『メメント』から学びます。非ネタバレなので、観たことない人でもオッケー。

 

 

おまけ:今日のエンジニアジョーク

 

次の講座へ

第14講: 映画『メメント』に学ぶコーディングでかなり重要なこと
プログラミングで意外に重要なことを、クリストファーノーラン監督の映画『メメント』から学びます。非ネタバレなので、観たことない人でもオッケー。