«前の日記(2006年03月01日) 最新 次の日記(2006年03月03日)» 編集

ema log


2006年03月02日 [長年日記]

_ [Programming][Ruby] エントリ草稿

  • リハビリをかねて1週間ほどで某落ちゲーのプロトタイプを作った。
  • Ruby + Ruby/SDL + RubyUnit + YAML + Logger
  • 全面的にテストを導入した。
    • RubyUnit による、単体テストとシナリオベースの機能テスト。単体テストはあまり作っていない → プロトタイプなので、構造体のようなクラスも少なくない
  • 幸い、仕様の詳細は定義済み → テストパターンを作りやすい!
    • リプレイ再生機能を作り、それを用いて機能テストを行う。
    • 「テスト開始フィールド、出現するブロック群、操作、期待されるフィールド」をパターンとして与える
    • 記述には YAML を使用 → 機能テストはユーザの立場から作るべきもの(Kent Beck?) → テストパターンの作成を容易に → パターンの外部ファイル化
    • 実際のテストシナリオの例

before から初めて、blocks が順に出現し、replay の操作を行った結果、after のフィールドが得られればテストをパスする。ちょっと長いけど、みればわかると思う。

  • 7回のバグ検出を実現(Subversion のログを眺めたところ)
  • 特にきわめて特殊な事例(回転入れ)のバグを検出 → 100% 再現可能なテストパターンを作って回帰テストを実現
  • 現在約80件のテストパターンを作ってすべてをクリア → それでもカバレッジが十分だとは思えない。もちろん作り足していけばいい。
    • テスト作成のコスト・バグ発見率 → Code Complete 参照。より上位で。バグを生みにくくする。
  • テストパターンのデバッグ
    • 残念ながら、テストパターンでもバグが発生しうる → 今回6つのパターンの作成をミスしている
    • 詳細なログ出力機構を埋め込み → 本質的には printf デバッグ。動作をトレース
    • ログを介することで、ソースコード・テストパターンのそれぞれから離れて少し客観的に観れる
    • 少々トリッキーなロギング → テスト時に assert に引っかかる時のみ詳細なログ出力を有効にして再実行 → トリッキーだが便利。強力な武器のひとつに
    • ログ出力の例:デバッガでトレースするのに似ている → 間接的な分、思いこみを排せた場合もあった
TEST FAILED at test_patterns/error_sample_field_test_1.yml
========================== FIELD DIFFERENCE ==========================
  expected       actual
[0500000000], [0000000000]
[5500000000], [0055500000]
[1500000000], [1005000000]
[1111111100], [1111111100]
[1111111110], [1111111110]
[1111111110], [1111111110]
[1111111110], [1111111110]
[1111111110], [1111111110]
[1111111110], [1111111110]
[1111111110], [1111111110]
[1111111110], [1111111110]
[1111111110], [1111111110]
[1111111101], [1111111101]
[1111111011], [1111111011]
[1111110111], [1111110111]
[1111101111], [1111101111]
[1111011111], [1111011111]
[1110111111], [1110111111]
[1101111111], [1101111111]
[1011111111], [1011111111]
[0111111111], [0111111111]
========================== STATUS LOG START ==========================
--- frame start
appear WAIT
NEW block is appeaed, color is 5
try to drop down 0 from 0
DROP down to 0
--- frame end
[0000000000]
[000***0000]
[1000*00000]
[1111111100]
[1111111110]
[1111111110]
[1111111110]
[1111111110]
[1111111110]
[1111111110]
[1111111110]
[1111111110]
[1111111101]
[1111111011]
[1111110111]
[1111101111]
[1111011111]
[1110111111]
[1101111111]
[1011111111]
[0111111111]
--- frame start
Block dropping

... (略) ...
  • テストのもう一つの狙い → リファクタリング
    • 動いているコードの変更 → 安全な「変更」のためにはバージョン管理と回帰テストが必須
  • プロトタイピングの結果、設計の誤り → Field クラスに責任が集中 → もし、完成させるならクラスに分解
    • とりあえず、Model / View / Controller に分解 → リファクタリング
      • 番兵 (Sentinel) を Model に押し込めたり etc...
    • 回帰テストが可能になっているために、バグを増やしにくい(ミスっても検出されやすい)
  • テスト記述方法のリファクタリング
    • 操作列(リプレイ)ではユーザフレンドリで直感的な書式を実現しているのに、何故かブロックでは抜け落ちている → まぁそんなもの
    • もっとユーザフレンドリに!!直感的に!!
    • マジックナンバーが残っている → 色/形から連想可能な文字で指定できるべき(Red,Blue,... / I, L, Z, S)
    • 既存のテストもスクリプトを組んで修正する
  • 最適化
    • 1個所だけブロックの幅・高さをキャッシュするように → Profile してみたらあまりにもコストが大きかった
    • 本質的には描画を差分描画にすれば、根本的に修正可能 → プロトタイプだからそこまでしない → 構想だけで未実装。
    • そもそも、60 FPS は悠々出ている
  • ログ出力コードのリファクタリング → メソッドの抽出

入力検査部に埋め込んでいるのだがを以下のようにして、ログ出力をより確実なものにした方が良いだろうか。より読みやすく、また、回転があった場合にログが必ず出力されるようになったと思う → 構想だけで未実装。

本日のツッコミ(全2件) [ツッコミを入れる]
_ いしも (2006年03月02日 15:28)

どうやら無事みたいやなw

_ ema (2006年03月02日 15:31)

睡眠時間が変な時間になってたりしてねぇw