39
デバッグ戦略 わかめ まさひろ(@v vakame) Androidを対象に説明するよ! 2011825日木曜日

デバッグ戦略

Embed Size (px)

Citation preview

Page 1: デバッグ戦略

デバッグ戦略わかめ まさひろ(@vvakame)

Androidを対象に説明するよ!

2011年8月25日木曜日

Page 2: デバッグ戦略

本日の内容

http://www.slideshare.net/vvakame/debugging-strategy

• 心構え

• 例外のデバッグ

• ロジックのバグのデバッグ

2011年8月25日木曜日

Page 3: デバッグ戦略

心構え

2011年8月25日木曜日

Page 4: デバッグ戦略

そもそも!!

バグを作らなければいい!!

2011年8月25日木曜日

Page 5: デバッグ戦略

それって…?

良い設計に勝る物なし!!

2011年8月25日木曜日

Page 6: デバッグ戦略

ミスしにくい設計に• 不可分なメソッド呼出しがあるならひとつにまとめる

• initA() と initB() があるなら init() を作成する。A, B はpublicにしない

• 間違って2回呼び出しちゃっても正しい状態になるように出来るといいな

• 冪等(べきとう) になるようにする• いつ呼んでも良いので条件式が減る

• 他にも色々あるよね…2011年8月25日木曜日

Page 7: デバッグ戦略

どちらがより安全?/** * 全てのbitmapの左上のピクセルを赤くする. * * @param bitmapArrays */static void dot1PixelA(Bitmap[][] bitmapArrays) { for (int i = 0; i < bitmapArrays.length; i++) { for (int j = 0; j < bitmapArrays[i].length; i++) { bitmapArrays[j][i].setPixel(0, 0, Color.RED); } }}

/** * 全てのbitmapの左上のピクセルを赤くする. * * @param bitmapArrays */static void dot1PixelB(Bitmap[][] bitmapArrays) { for (Bitmap[] bitmapArray : bitmapArrays) { for (Bitmap bitmap : bitmapArray) { bitmap.setPixel(0, 0, Color.RED); } }}

for

for-each

2011年8月25日木曜日

Page 8: デバッグ戦略

どちらがより安全?/** * 全てのbitmapの左上のピクセルを赤くする. * * @param bitmapArrays */static void dot1PixelA(Bitmap[][] bitmapArrays) { for (int i = 0; i < bitmapArrays.length; i++) { for (int j = 0; j < bitmapArrays[i].length; i++) { bitmapArrays[j][i].setPixel(0, 0, Color.RED); } }}

/** * 全てのbitmapの左上のピクセルを赤くする. * * @param bitmapArrays */static void dot1PixelB(Bitmap[][] bitmapArrays) { for (Bitmap[] bitmapArray : bitmapArrays) { for (Bitmap bitmap : bitmapArray) { bitmap.setPixel(0, 0, Color.RED); } }}

for

for-each

2011年8月25日木曜日

Page 9: デバッグ戦略

常に使えるわけじゃないBitmap[][] bitmapArrays = new Bitmap[10][10];for (int i = 0; i < bitmapArrays.length; i++) { for (int j = 0; j < bitmapArrays[i].length; j++) { bitmapArrays[i][j] = Bitmap.createBitmap(3, 3, Config.ARGB_8888); }}

添字が必要な場合はしょうがないね…

大事なのは、やり方が複数ある時、一番バグらなさそうな方法を選ぶこと

2011年8月25日木曜日

Page 10: デバッグ戦略

これも関係あるんだよ!

ADTは最新版を使おう!

自動でデバッグ可能な設定にしてくれたり。2011/08/25時点では最新は rev12

2011年8月25日木曜日

Page 11: デバッグ戦略

例外のデバッグ

2011年8月25日木曜日

Page 12: デバッグ戦略

うっかり例外• アプリが落ちる!

• メソッドを呼び出す順番を間違えた

• 境界値を超えた値を渡しちゃった

• nullなのにアクセスしようとした

2011年8月25日木曜日

Page 13: デバッグ戦略

爆発箇所の特定• LogCat を見て調べる

2011年8月25日木曜日

Page 14: デバッグ戦略

何が書いてあるの?• エラー発生時の実行箇所と呼出し階層

L07@OverrideL08public void onCreate(Bundle savedInstanceState) {L09 super.onCreate(savedInstanceState);L10 setContentView(R.layout.main);L11L12 try {L13 throw new NullPointerException();L14 } catch (Exception e1) {L15 try {L16 throw new IllegalArgumentException(e1);L17 } catch (Exception e2) {L18 try {L19 throw new IllegalStateException(e2);L20 } catch (Exception e3) {L21 throw new RuntimeException(e3);L22 }L23 }L24 }L25}

真犯人!

一番下のCausedが一番怪しい!2011年8月25日木曜日

Page 15: デバッグ戦略

何が書いてあるの?• 注目すべきポイントと発生原因

L08@OverrideL09public void onCreate(Bundle savedInstanceState) {L10 super.onCreate(savedInstanceState);L11 setContentView(R.layout.main);L12 requestWindowFeature(Window.FEATURE_NO_TITLE);L13}

L11とL12逆にしろ!

一番最初に出てくる自分が作ったクラスを見る2011年8月25日木曜日

Page 16: デバッグ戦略

どこがバグかな?

L22が容疑者…?L09@OverrideL10public void onCreate(Bundle savedInstanceState) {L11 super.onCreate(savedInstanceState);L12L13 LinearLayout layout1 = new LinearLayout(this);L14 LinearLayout layout2 = new LinearLayout(this);L15 LinearLayout layout3 = new LinearLayout(this);L16 Button button = new Button(this);L17L18 layout1.addView(layout2);L19 layout2.addView(layout1);L20 layout3.addView(button);L21L22 setContentView(layout1);L23}

layout1 → layout2 → layout1 !?layout1 → layout2 → layout3にしたかったんじゃ…

2011年8月25日木曜日

Page 17: デバッグ戦略

“状態” がキーワード• ご飯食べたい!(`・ω・´)

• お米を洗う

• 炊飯器にセットする

• 開始ボタン押し忘れる ←バグ

• ……しばらくお待ち下さい……

• ご飯炊けてない… orz ←エラー発生2011年8月25日木曜日

Page 18: デバッグ戦略

“状態” がキーワード• バグの原因はエラー発生箇所より前!

• 適切に状態を変化させたかな?

• バグが発生しにくい設計を心がける

• お米入れて蓋を閉めたら自動で炊飯開始する設計ならご飯食べられた…

• 人のコード見て良いとこパクる

2011年8月25日木曜日

Page 19: デバッグ戦略

状態を解析するvoid sort() { List<String> list = new ArrayList<String>(); list.add("cupcake"); list.add(null); list.add("donuts"); list.add(null); list.add("froyo");

Collections.sort(list, new Comparator<String>() { @Override public int compare(String str1, String str2) { if (str1 == null) { return -1; } return str1.compareTo(str2); } });

Log.d("Debug", list.toString());}

NullPointerExceptionが発生する…

LogCatでどの行で発生しているかまでは分かる…2011年8月25日木曜日

Page 20: デバッグ戦略

状態を解析する

デバッグで実行

指定の例外が発生したら実行を中断

2011年8月25日木曜日

Page 21: デバッグ戦略

状態を解析する

str2がnullの時発生String#compareTo(String) にnullを渡してはいけないらしい…

2011年8月25日木曜日

Page 22: デバッグ戦略

実演

まずはNPE(NullPointerException)で止まる設定から!

2011年8月25日木曜日

Page 23: デバッグ戦略

ロジックのバグのデバッグ

2011年8月25日木曜日

Page 24: デバッグ戦略

バグがある…??public class Util {

/** * 渡された2つのリストを1つにまとめたリストを作成し返します. * @param list1 1つ目のリスト * @param list2 2つ目のリスト * @return 1つにまとめたリスト */ public static List<Object> merge(List<Object> list1, List<Object> list2) { list1.addAll(list2); return list1; }

/** * 渡された複数のリストを1つにまとめたリストを作成し返します. * @param lists まとめたい複数のリスト * @return 1つにまとめたリスト */ public static List<Object> merge(List<?>... lists) { List<Object> result = new ArrayList<Object>(); for (List<?> list : lists) { result.addAll(list); } return result; }}

2011年8月25日木曜日

Page 25: デバッグ戦略

とりあえずテスト書くpublic void test() { List<Object> list1 = new ArrayList<Object>(); list1.add("a"); list1.add("b"); List<Object> list2 = new ArrayList<Object>(); list2.add(1); list2.add(2); List<Object> list3 = new ArrayList<Object>(); list3.add(1.25); list3.add(2.5);

List<Object> merged1 = Util.merge(list1, list2); List<Object> merged2 = Util.merge(list1, list2, list3);

assertEquals(merged1.size(), 4); assertEquals(merged1.get(0), "a"); assertEquals(merged1.get(1), "b"); assertEquals(merged1.get(2), 1); assertEquals(merged1.get(3), 2);

assertEquals(merged2.size(), 6); assertEquals(merged2.get(0), "a"); assertEquals(merged2.get(1), "b"); assertEquals(merged2.get(2), 1); assertEquals(merged2.get(3), 2); assertEquals(merged2.get(4), 1.25); assertEquals(merged2.get(5), 2.5);}

2011年8月25日木曜日

Page 26: デバッグ戦略

とりあえずテスト書くpublic void test() { List<Object> list1 = new ArrayList<Object>(); list1.add("a"); list1.add("b"); List<Object> list2 = new ArrayList<Object>(); list2.add(1); list2.add(2); List<Object> list3 = new ArrayList<Object>(); list3.add(1.25); list3.add(2.5);

List<Object> merged1 = Util.merge(list1, list2); List<Object> merged2 = Util.merge(list1, list2, list3);

assertEquals(merged1.size(), 4); assertEquals(merged1.get(0), "a"); assertEquals(merged1.get(1), "b"); assertEquals(merged1.get(2), 1); assertEquals(merged1.get(3), 2);

assertEquals(merged2.size(), 6); assertEquals(merged2.get(0), "a"); assertEquals(merged2.get(1), "b"); assertEquals(merged2.get(2), 1); assertEquals(merged2.get(3), 2); assertEquals(merged2.get(4), 1.25); assertEquals(merged2.get(5), 2.5);}

ここで size が 8 になってる!

2011年8月25日木曜日

Page 27: デバッグ戦略

実行を追ってみよう!

Debug As ... で実行

実行を途中で止められる!2011年8月25日木曜日

Page 28: デバッグ戦略

デバッグ中の操作方法

試したほうが早いかも。

• F8 実行を再開

• F5 1行分実行する(メソッドがあったら潜る)

• F6 1行分実行する(メソッドがあったら飛ばす)

• F7 処理中のメソッドを全て実行

2011年8月25日木曜日

Page 29: デバッグ戦略

実演

なんでサイズが8なのかな…?

2011年8月25日木曜日

Page 30: デバッグ戦略

結論

予期せぬ副作用 (状態の変更)が発生している=バグ2011年8月25日木曜日

Page 31: デバッグ戦略

知っておきたいテクニック

• 変数の中身見られる• クラス変数, インスタンス変数, ローカル変数• Variablesのビューや、マウスカーソルのっけるとか

• 実は変数の中身も変えられる• 中身変えて動作の実験したりとかも出来る

2011年8月25日木曜日

Page 32: デバッグ戦略

知っておきたいテクニック

世界を書き換えるパワーが…

┣¨┣¨┣¨┣¨┣¨┣¨┣¨┣¨...2011年8月25日木曜日

Page 33: デバッグ戦略

知っておきたいテクニック呼出し元の値チェックも可能

右クリック→Inspectから選択範囲の再実行とかも可能

2011年8月25日木曜日

Page 34: デバッグ戦略

知っておきたいテクニック

条件付きブレークポイント

2011年8月25日木曜日

Page 35: デバッグ戦略

まとめ• ちょっとずつ実行できる

• 変数の中身見える

• 変数の書き換えもできる

• スタックトレースもさかのぼれる

• 好きなメソッドの実行もできる

• デバッグ中にコード書いて実行さえ可能2011年8月25日木曜日

Page 36: デバッグ戦略

超☆やりたい放題

2011年8月25日木曜日

Page 37: デバッグ戦略

オマケ OpenGLのデバッグ

2011年8月25日木曜日

Page 38: デバッグ戦略

気合で頑張れ!

http://t.co/bet4051

OpenGL本著者に聞いてみた

2011年8月25日木曜日

Page 39: デバッグ戦略

なにか質問は?

実践を重ねると勘が働くようになるよ 最初の頃は時間がかかってしまうもの

2011年8月25日木曜日