皆さん「バグ」直してますか?
特にプログラムを始めたばかりの人は見たくもないと思ってるかもしれません「バグ」。
見たくないですよね〜。わかります。
while (ture) { print("バグ"); } // つれー
そんな「バグ修正が苦手!」という方や「バグ修正なんかつまらない!」という方向けにバグ修正のアプローチを朝までには伝えることができたらと思います。
この記事を読み終わった後、きっとあなたはバグを修正したくてウズウズすることでしょう。
ちょっと長いので逆から読んでもらっても構わないです。
- エラーログを読もう
- 再現手順を確立させよう
- 何が原因かを考えてみよう
- 仮説を検証しよう
- 修正案を立てよう
- 修正箇所の影響範囲を調べよう
- 修正案を元に修正しよう
- テストをしよう
- コードをレビューしてもらおう
- 修正をリリースしよう
- まとめ
- 初めまして私はCzといいます
エラーログを読もう
なんといっても、まずはエラーログを読みましょう。ここには発生した時点の情報がたくさん詰まっています。
ログを読まずにバグ修正力が身につくことなんてまずありません。我慢して読んでみてください。
ログを読むときの観点
- このエラーはどういう意味か?
- このエラーはどんなときに発生するか?
- このエラーがなぜ発生したか?
「英語だから分かんないよ!!(憤怒)」となる方もいるかもしれませんが安心してください。ただの単語の羅列です。
それでも難しい場合はGoogle先生に頼るのです。では行きますよ!せーの...
Hey, Siri!!
ポイント
- 情報を集めることに専念する。(疑問を持つ → 解消する)
- 英語がわからなければGoogle翻訳。いっそエラーメッセージそのままググってみる。
- stackoverflowという検索上位にヒットするサイトを避けない。(英語だけど内容は難しくないよ)
- コードはまだ触らない。
再現手順を確立させよう
再現手順とは、バグを発生させる手順のことです。
再現手順を確立させる目的は2つあると思っています。
- 修正後に本当に直ったか同じ手順で確認するため。
- 問題解決を行うためのヒントを得るため。
2. についてどういうことかというと、例えば...
「A → B → C」という手順で実行した時は問題が発生しないけれども、
「A → B → D → C」という手順で実行した時は問題が発生するとなれば、
「D」の入力に問題があるのかな?それとも「B」の出力かな?
と色々予想がつくと思います。
問題発生時は必ず正常時との差分が発生しています。
この差分の発生箇所に根本原因が隠れていることが多いので再現手順を確立させることは重要なのです。
なお、タイミングによっては再現したりしなかったりということがあると思います。
こういう時は再現率も記録しておきましょう。
10回中1回起きるなら「再現率:1/10」といった感じで残しておきます。
これも調査に必要な情報となります。
ポイント
- 再現手順を確立させる。
- コードはまだ触らない。
何が原因かを考えてみよう
上で集めた情報を元に何が原因かを考えてみましょう。
この時コードを触りながらではなく頭で考えてください。
考えがまとまらない場合は、何が足りなくて考えがまとまらないかを考えてください。
そして足りない情報はあらゆる手を使って調べ、また考えてください。
さらに、これが「根本原因だ!」と言えるかを自分に問うてください。
そしてさらに考えてください...
あなたはきっとこう思ってるはずです。
「うわぁなんだか宗教じみてきたぞ〜」と。
ポイント
- 根本原因(仮説)を他人に理由付きで説明できるようにする。
- 15分考えてわからなかったら周りに聞く。
- 他人を疑う前に自分を疑う。
仮説を検証しよう
仮説を元にそれが正しいか(根本原因が間違っていないか)を検証します。
検証方法としては以下のような感じがほとんどだと思います。
「問題と思われるモジュールなどの入力値を、問題が起こるであろう値(仮説で立てた値)に無理やり変更し実行する」
なお、入力値とはモジュールが参照しうる動的変数全てのことを指します。
(関数の引数はもちろんのこと、クラスのメンバ変数や、グローバル変数も対象となります。)
ポイント
- 根本原因を明確化する。(余計な修正をしないため)
- 入力値=参照しうる全ての動的変数。(全ての値が静的なら問題は起きないはず!)
- 非同期処理によるタイミング問題は別のアプローチが必要(割愛)
修正案を立てよう
「ここまでなげーよ!」と思ったかもしれません。(少なくとも私は思っています。)
実はここがバグ修正で一番楽しいところです!おめでとうございます!(ありがとうございます)
初心者のあなた(決めつけ)は、NullPointerExceptionが発生した時きっと...
「エラーが発生しないようにNullチェックでも入れておこう」
と安易な考えで対処してきたかもしれません。
でも今のあなたは問題の発生原因を説明できるようになっているはずです。
ということはあなたはNullPointerExceptionではなく、根本原因に目が向いているはずです。
根本原因に対してどう修正すれば良いかを考えてみましょう。
できれば案は2つ以上あったほうが比較できるので良いです。
ポイント
- 根本原因の箇所がどうあるべきかを考えながら修正案を考える。
- 修正案を2つ以上出すことにより、案同士で比較できるようになるので案の精度が高まる。
- 複数人で修正案を考えることにより更に案の精度が高まる。
修正箇所の影響範囲を調べよう
修正箇所がもし複数の箇所から呼ばれるメソッドや関数だった場合、影響を受ける箇所が複数あるということになります。
バグ修正とはバグを修正しつつ今までの動きを変えないことです。
もし、今までの動きが変わってしまうようならそれは以下のどちらかになります。
- デグレ
- 仕様変更
デグレを起こさないためにも修正による影響範囲を把握し、リストアップしておきましょう。
ポイント
- デグレは悪。
- バグ修正ついでの仕様変更は絶対やめたほうがいい。(同じコミットなら尚更)
- 影響範囲を調べることで修正案が揺らぐ(変わる)ことがある。
修正案を元に修正しよう
実際に修正してみましょう。
今ある武器は「揺るぎない根本原因」と「完璧な修正案」です。
今までずっとコードを触るのを我慢してきたのですから思いっきり楽しんでください。
仮にもし根本原因が間違っていたり、修正案が甘かったりした場合は一旦戦場から身を引きましょう。
もしこのまま足掻こうものならばおそらく沼にハマることでしょう...
ポイント
- 楽しみながらコードを触る。
- 沼にハマりそうな時は一旦引く。
- 実装の不明点は常に取り除いておく。(わからないまま実装しない)
テストをしよう
修正のテストを行います。
ここでの観点は以下の通りです。
- 期待通り動作する。
- 影響範囲も正しく動作する。
そして行なったテストは必ず記録として残しておいてください。 これを行わないと自分の修正に自信が持てなくなってしまいます。
ポイント
- 実施したテストのエビデンスを残す。
- 「なおりました!」と自信を持って言うためのテストを行う。(テストケースを見極める)
コードをレビューしてもらおう
コードレビュー楽しいですよね〜。
えっ!?楽しくない??ズタボロに言われるのが嫌??
わかりますおじさん「わかります」
レビューはプログラマ同士が目の前のコードに対して会話ができる場所です。
でもそれが苦手ということはきっと以下に当てはまるのではないのでしょうか。
- 自分のコードを説明できない。
- 自分のコードに自信がない。
- 眠い
要約すると、
- 説明できない = 自分が何をしようとしているかわかっていない(コピペかな?)
- 自信がない = 情報不足、テスト不足
- 眠い = 睡眠不足
でもここまで苦痛に耐えながら読んでくれたあなたは、きっと自分の修正に対し説明できるし自信もあるはずです!
もちろんレビュー指摘を一切受けなくなるということではありません。
でもきっと受けるレビューは「批判」ではなく「提案」に感じるようになります。
こうなれば「レビューたのしーー!!」って叫べるかもしれません。
さぁ!言ってみましょう!!今すぐベランダの窓を開けて!!!
(あっもしもし、警察ですか?)
ポイント
- 不安要素を取り除く。
修正をリリースしよう
正直ここまで長すぎて書くのにちょっと疲れてしまいました。 プロジェクトのルールに従ってリリースしてください。
ポイント
- プロジェクトのルールに従う。
- みんなの喜ぶ顔を想像する。
まとめ
バグ修正一つにしても様々なフェーズがあります。
根本原因を特定するための「情報収集」「仮説立て」「検証」
修正を行うための「情報収集」「修正案の立案」「実施」
そして「テスト」「リリース」。
「ちょっとやること多くありません??」
まぁでもだからこそ楽しいし、やりがいがあると思います。
ここまで読んでくださった方々が少しでもバグ修正の楽しみを知っていただけたら幸いです。
初めまして私はCzといいます
タイトルを「アプローチ」にするか「メソッド」にするか「方法」にするか「手順」にするか結構迷いました。
べっ、別にここに書いたのは検索ワードを増やそうって訳じゃないからねっ!
\\『明日のはたらくを創る』仲間を募集中です!! //
919.jp