やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

デバッグだけではコスト最小化されない

単体テストを行うとコスト最小化できることに疑問を投げかけたが、真であることが補強された。

問題提起

前回、単体テストを行うことでコストが最小化することを証明した。しかし本当か?「デバッグを行うことでコストが最小化する」ではないだろうか?

項目 内容
疑問 コストの大小関係は「デバッグ < 単体テスト」では?
結論 コストの大小関係は「単体テスト < デバッグ」である

結論

デバッグだけではコスト最小化できない。

ケース コスト コスト値
単体テストのみ 単体テストコスト 2
デバッグ + 単体テスト デバッグコスト + 単体テストコスト 3 (1 + 2)
デバッグのみ デバッグコスト + 単体テストの不作為コスト 6 (1 + 5)

テスト方法一覧

プログラムが正しく動作することを確認する方法には以下のものがある。

名前 内容
デバッグ コードを1行ずつ実行し、状態を確認しながら誤りを発見する。
単体テスト 関数単位でその入出力や実行ルートの全パターンを網羅し期待通りか確認する。
結合テスト 関数やクラスなどを呼び出して結合した状態で期待通りか確認する。

単体テストはテストコード実装によりテストを再現可能にできる。テストコードはプログラムの価値を高める。それは前回で証明された。しかしデバッグは再現可能な手順を記録できない。デバッグ単体テストの不作為コストを抱えている。

動作確認工程

順序 テスト工程 確認タイミング 内外
1 デバッグ コード実行中 ホワイトボックステスト
2 ログ確認 コード実行終了後 ブラックボックステスト

正しく動作することを確認するには上記の順に、上記の行為を行うものである。

テスト工程

順序 テスト工程
1 単体テスト
2 結合テスト
順序 テスト工程
1 単体テスト|テストコードにより品質確認できる(再現時のコスト最小化)
2 結合テスト|テストコードにより自動化するよう実装するコストのほうが大きいため手動でテストすることが多い

コスト定量

デバッグのコストを定量化するのは難しい。以下の項目が変わるとデバッグの内容や方法も大きく変わる。

CUIデバッガとIDEなどによるGUIデバッガとでは操作方法も表示も全く違う。その操作方法について学習する必要がある。また、言語ごとにデバッガも異なる。それらについて未知のため定量化できない。定性すら見えない。ただし、推し量ることはできる。

デバッガで確認できることは単体テストでも確認できるはずである。デバッガは単体テストと違い、テストコードで再現可能な形に記録できない。デバッグ単体テストの不作為コストを抱えていることになる。単体テストをすれば解消されるが、単体テストすればデバッガの確認内容も解消できるのだから、デバッグをやるより、デバッグをやらず単体テストのみ行うほうがコストが少ないはず。

ただ、デバッグで確認できることを単体テストで確認するためには、ホワイトボックステストを行う必要がある。関数内部のコード1つ1つを考慮しパターン網羅する必要がある。これができればデバッグをする必要なくなるし、単体テストの不作為コストも解消される。ただしホワイトボックステストのコストが生じる。ブラックボックステストだけのときよりテストケースが増える。また、実行ルートの網羅などテストケースを考えるコストも増える。

それでも、結合後のコードからデバッグ確認するよりはコストが低いと考える。

コスト コスト値
デバッグ 1
単体テスト(ブラックボックステスト) 2
単体テスト(ホワイトボックステスト) 3
結合テスト 4
単体テスト不作為 5

コスト大小関係は「結合テスト < 単体テスト不作為」である。下流でせき止められず上流工程にながれてしまうほど後戻り作業が増えて修正コストが肥大化するから。単体テスト結合テストより下流なので、上流への影響がより大きい。よって「結合テストコスト < 単体テスト不作為コスト」である。

コスト大小関係が「結合テスト < 単体テスト」になっている。これについては正当性の根拠なし。そもそも結合テストの定性を洗い出していないため不透明。今回は単体テストの優位性を否定してデバッグを優位に立たせたいので、単体テストを否定しやすいようこの値にする。

ケース コスト コスト値
単体テスト([ブラック/ホワイト]ボックス両方) 単体テストコスト 5 (2+3)
結合テスト + デバッグ 結合テスト + デバッグコスト + 単体テスト不作為コスト 10 (4+1+5)

デバッグ不作為コストは存在しない。デバッグで確認できることは単体テストでも確認できるから。単体テストの段階では結合テスト不作為コストがあるようにもみえる。しかし順当に進めば次に結合テストを行うので「不作為(あえて行わない)」でなはく「まだ実行していない」だけ。実行する予定なので解消される。そのときは結合テストコストが加算される。

ただ、単体テストでは関数のブラックボックステストしかできない。関数における入出力のテストしかできない。関数内のある時点での内部変数値がいくつであるかを確認できない。結合後はその確認が必要になる。結合したときの順序や組合せが間違っていて期待通りにならない不具合があるかもしれない。結合後のコードから問題箇所を特定するには、デバッグによるホワイトボックステストが必要である。

ただ、単体テストができない、またはしづらい状況がある。privateなメソッドやインナークラス、結合後の局所確認である。これについてはデバッガでの確認が有用かもしれない。

たとえばプログラミング言語Pythonなら、デバッグをするより単体テストをしたほうがコストが低いと思われる。

デバッグコストの定性

デバッグ

デバッグコストの定性

  • 準備コスト
    • 確認コード作成コスト
    • デバッガ確認準備コスト
  • 実行コスト
  • 結果確認コスト

確認コード作成コストの定性

  • 確認したい値を出力するコードを埋め込む
    • print()
    • ログ関数を埋め込む
      • ログレベルをDEBUGにする
  • 値が期待値か確認する

実行コスト

http://racchai.hatenablog.com/entry/2016/05/30/070000 http://postd.cc/debugging-courses-should-be-mandatory/ http://myenigma.hatenablog.com/entry/2015/05/25/221850

修正コスト

  • 案件コード修正コスト

動作確認せずに案件コードを書いたときに生じる修正コスト。

開発工程

順序|工程 1|コーディング| 2|デバッグ| 3|単体テスト 4|結合テスト 5|公開

ファイル設計 モジュール設計 クラス設計 メソッド設計 アルゴリズム設計