Upload
masahiro-wakame
View
3.006
Download
0
Embed Size (px)
Citation preview
デバッグ戦略わかめ まさひろ(@vvakame)
Androidを対象に説明するよ!
2011年8月25日木曜日
本日の内容
http://www.slideshare.net/vvakame/debugging-strategy
• 心構え
• 例外のデバッグ
• ロジックのバグのデバッグ
2011年8月25日木曜日
心構え
2011年8月25日木曜日
そもそも!!
バグを作らなければいい!!
2011年8月25日木曜日
それって…?
良い設計に勝る物なし!!
2011年8月25日木曜日
ミスしにくい設計に• 不可分なメソッド呼出しがあるならひとつにまとめる
• initA() と initB() があるなら init() を作成する。A, B はpublicにしない
• 間違って2回呼び出しちゃっても正しい状態になるように出来るといいな
• 冪等(べきとう) になるようにする• いつ呼んでも良いので条件式が減る
• 他にも色々あるよね…2011年8月25日木曜日
どちらがより安全?/** * 全ての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日木曜日
どちらがより安全?/** * 全ての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日木曜日
常に使えるわけじゃない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日木曜日
これも関係あるんだよ!
ADTは最新版を使おう!
自動でデバッグ可能な設定にしてくれたり。2011/08/25時点では最新は rev12
2011年8月25日木曜日
例外のデバッグ
2011年8月25日木曜日
うっかり例外• アプリが落ちる!
• メソッドを呼び出す順番を間違えた
• 境界値を超えた値を渡しちゃった
• nullなのにアクセスしようとした
2011年8月25日木曜日
爆発箇所の特定• LogCat を見て調べる
2011年8月25日木曜日
何が書いてあるの?• エラー発生時の実行箇所と呼出し階層
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日木曜日
何が書いてあるの?• 注目すべきポイントと発生原因
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日木曜日
どこがバグかな?
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日木曜日
“状態” がキーワード• ご飯食べたい!(`・ω・´)
• お米を洗う
• 炊飯器にセットする
• 開始ボタン押し忘れる ←バグ
• ……しばらくお待ち下さい……
• ご飯炊けてない… orz ←エラー発生2011年8月25日木曜日
“状態” がキーワード• バグの原因はエラー発生箇所より前!
• 適切に状態を変化させたかな?
• バグが発生しにくい設計を心がける
• お米入れて蓋を閉めたら自動で炊飯開始する設計ならご飯食べられた…
• 人のコード見て良いとこパクる
2011年8月25日木曜日
状態を解析する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日木曜日
状態を解析する
デバッグで実行
指定の例外が発生したら実行を中断
2011年8月25日木曜日
状態を解析する
str2がnullの時発生String#compareTo(String) にnullを渡してはいけないらしい…
2011年8月25日木曜日
実演
まずはNPE(NullPointerException)で止まる設定から!
2011年8月25日木曜日
ロジックのバグのデバッグ
2011年8月25日木曜日
バグがある…??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日木曜日
とりあえずテスト書く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日木曜日
とりあえずテスト書く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日木曜日
実行を追ってみよう!
Debug As ... で実行
実行を途中で止められる!2011年8月25日木曜日
デバッグ中の操作方法
試したほうが早いかも。
• F8 実行を再開
• F5 1行分実行する(メソッドがあったら潜る)
• F6 1行分実行する(メソッドがあったら飛ばす)
• F7 処理中のメソッドを全て実行
2011年8月25日木曜日
実演
なんでサイズが8なのかな…?
2011年8月25日木曜日
結論
予期せぬ副作用 (状態の変更)が発生している=バグ2011年8月25日木曜日
知っておきたいテクニック
• 変数の中身見られる• クラス変数, インスタンス変数, ローカル変数• Variablesのビューや、マウスカーソルのっけるとか
• 実は変数の中身も変えられる• 中身変えて動作の実験したりとかも出来る
2011年8月25日木曜日
知っておきたいテクニック
世界を書き換えるパワーが…
┣¨┣¨┣¨┣¨┣¨┣¨┣¨┣¨...2011年8月25日木曜日
知っておきたいテクニック呼出し元の値チェックも可能
右クリック→Inspectから選択範囲の再実行とかも可能
2011年8月25日木曜日
知っておきたいテクニック
条件付きブレークポイント
2011年8月25日木曜日
まとめ• ちょっとずつ実行できる
• 変数の中身見える
• 変数の書き換えもできる
• スタックトレースもさかのぼれる
• 好きなメソッドの実行もできる
• デバッグ中にコード書いて実行さえ可能2011年8月25日木曜日
超☆やりたい放題
2011年8月25日木曜日
オマケ OpenGLのデバッグ
2011年8月25日木曜日
なにか質問は?
実践を重ねると勘が働くようになるよ 最初の頃は時間がかかってしまうもの
2011年8月25日木曜日