設計レベルでの見直し、リファクタリングだ!ビットフィールド比較をやめて文字列比較にしよう。

  • 0
    Like
  • 2
    Comment

    問題の発覚

    ぜったい こんな記事 誰得なんだが、こんなことがあった。
    201701291517gif42.gif
    この並んだ箱の中で、角を持った動物は Ox、Unicorn、 Yak だ。

    この四角、ビットフィールドで 角を持っている、といった項目をどんどん増やしていこうと思ったんだが……。
    201701291656a1.png
    int型って 32bit だっけ? 32個しか項目を持てないじゃないか。

    100個とか 200個を超えるタグを使いたい。
    こうして運用で頓挫して 基本設計からの見直しだ。要点をまとめよう。

    ビットフィールドは、複数の項目を例えば int型1個 に収めることができてメモリは省エネだし、比較が1回で済んで速い

    201701291656a2b.png
    こうやって 3つの項目を「|」でつないで 1個分 に納めることもできる。
    項目が32個未満ならこれでよかった。

    これを止めて、単に文字列の総当たり比較にしたい。

    201701291656a4b.png
    一気に バッ と変えると 一発でうまくいけばいいが、1個所間違えたら それを探す時間がもったいない。
    そこで、「1個所の間違いを探す時間」と「2度手間」をトレードオフし、段階的に進める。

    まず ソースコードから タグに置き換えたい列挙型の使用部分を一掃し、
    文字列定数に置き換えていく。そのとき コンバーターを使う。

    つまりこうなる

    201701291656a5.png
    第1ステップとして、データ構造にはいっさい手を付けず、コードから列挙型を消す。
    このとき、元に何が書いてあったかは消さずに コメントにして置いておく。

    自信があれば 文字列全置換 を連発してもいいかもしれない。

    進捗が進めば 引き続き 書き足していきたい。

    Find All Reference

    201701291656a6b.png

    列挙型のメンバーを右クリックし、[Find All Refernce]をクリックすると
    残り何カ所あるか分かったり、クリックでそこへ飛べるので、
    これで全てのメンバーを コードから消し飛ばしたことを確認する。

    Unit test

    201701291656a7.png
    コードをいじったら Unityのメニューから [Window] - [Editor Tests Runner] をクリックして
    ユニット・テストを実行する。
    キータイピング・ミスがあるようなので直す。

    進捗が進めば 引き続き 書き足していきたい。

    さあ修正だ

    201701291656a8a.png
    どのファイルの何行目で、どう間違えたのか下に出ている。

    201701291656a9b.png
    Visual Studio 2015 で [Ctrl] + [G] キーを押すと 行番号を指定して飛べる。
    G は Gyo ではなくて Go To Line の頭文字な。

    201701291656a10a.png
    元のコードをコメントとして残してあるので、カンマと 縦棒の打ち間違え ということが分かる。

    まあ別に コメントに残さなくても ソースコード丸ごと バックアップを取って 見返してもいいか。

    Asertを書いておけば、違ったところで分かる

    201701291656a11b.png
    なんか2匹足りないな……。

    201701291656a12b.png
    タイポがある。 キータイピングしてないで、バックアップ&全置換の方が良かった。

    201701291656a13.png
    オール・グリーン。これで コードをいじった結果、勘所では 前と同じ挙動をしている。
    ユニットテストが通ることを1つの区切りとして バックアップを残しつつ、段階的に 置き換えを進めていく。

    進捗が進めば 引き続き 書き足していきたい。

    ビットフィールドと HasFlag を外したい

    201701291656a14b.png
    次にやりたいのは、このOR結合を外すことだ。ビットフィールドの何桁目のビットを立てるか、をつなげているものだ。

    201701291656a15b.png
    ビットフィールドのどのビットが立っているかは HasFlag( ) メソッドで調べることができる。

    文字列の総当たり検索ではこの OR結合、HasFlag( ) は使えないので外すことにする。
    201701291656a16b.png
    同じことをしようとすると、使用メモリも増えるし、ループの実行回数も増える。
    省メモリと実行速度を捨てて 32項目の壁を突破したい。

    201701291656a17b.png
    さっきと同じ理屈で、置き換えていく。

    201701291656a18.png
    ユニットテストをすると 1件のエラーがある。

    201701291656a19b.png
    今度は 縦棒を カンマに置き換えたいのだった。

    201701291656a20.png
    よし、直ったぞ。

    進捗が進めば 引き続き 書き足していきたい。

    文字列の比較なんか遅い、ハッシュを使おう

    201701291656a21b.png
    これを、

    201701291656a22b.png
    こうする。せっかくだし、アニメーターのハッシュを作るやつを使わせてもらおう。

    201701291656a23.png
    へぇ、こんなもんで代替できるのか。

    進捗が進めば 引き続き 書き足していきたい。

    キータイピング量を減らそう

    201701291656a24b.png
    さっきのプログラムで うまくいくことが分かったので、こうした。

    201701291656a25.png
    こういうコンバーター1つ作っておくだけで キータイピングを減らせて楽できる。
    Ease(イーズ)プログラミングしていこう。

    進捗が進めば 引き続き 書き足していきたい。

    キータイピング量をもっと減らそう

    201701291656a26.png
    タグの キータイピング量を減らそうと思って こんな書き方にした。

    そうではない

    こんなんでは全然ダメだ! こうだ!
    201701291656a27.png
    C# や Unity の文化を壊さない程度に短くし、まあまあ すっきりしている。

    201701291656a28.png
    ユニットテストもOK。

    これだけシンプルになれば、リファクタリングした甲斐もあったというものだろう。

    ソース公開中 Open source

    https://github.com/muzudho/KifuwarabeFighter2