分岐
「条件分岐はない方がいい。」
開発を手伝ってくれている友人に、Web で使うディスクロージャー トライアングルの実装をお願いした。Web アプリに詳しい訳ではない彼が、苦労して試行錯誤の上で作ってくれたのがこれだ。
// キャッシュ img_expanded = "expanded.gif"; img_collapsed="collapsed.gif"; new Image().src = img_expanded; new Image().src = img_collapsed; // 展開 function expand(obj) { document.getElementById(obj+"i").src = img_expanded; // img タグ src 属性の変更 document.getElementById(obj).className = 'expanded'; // style タグ display 属性の変更 } // 圧縮 function collapse(obj) { document.getElementById(obj+"i").src = img_collapsed; // img タグ src 属性の変更 document.getElementById(obj).className = 'collapsed'; // style タグ display 属性の変更 } // 展開・圧縮の切り替え function dtSwitch(obj) { // オブジェクトが取得できるかどうか if (document.getElementById && document.getElementById(obj) != null) { nodeState = document.getElementById(obj).className; } if (nodeState == 'collapsed') { expand(obj); } else { collapse(obj); } }
スタイルシートの属性を切り替えて、表示、非表示をコントロールする仕組みとなっている。十分に機能しているし、通常であればこれで受け入れているところなのだが、二つの関数 expand と collapse がほとんど同じような処理となっていて冗長に感じたため、書き直してもらうことにした。
expand と collapse の中をよく見ると、式の左辺が同じで右辺が異なるだけなので、右辺をパラメータとして受け取るようにすれば一つの関数で済むようになる。実は右辺の値は状態に依存した静的な情報 (実行時ではなく、開発時に決定している) なので、ハッシュに入れて状態をキーにして引っ張れるようにすれば、パラメーターで受け取る必要もなくなる。そんなサンプルを Ruby で書いて渡して、書き直してもらったのがこれ。
// 状態管理情報用クラス function state(_img, _className) { this.img = _img; this.className = _className; new Image().src = _img; // 画像をキャッシュ } // 状態管理情報の定義 var stateMap = new Object(); stateMap["expanded"] = new state("collapsed.gif", "collapsed"); stateMap["collapsed"] = new state("expanded.gif", "expanded"); // 展開/巻き上げの切り替え function toggle(blockID, imageID) { // 準備 block = document.getElementsByName(blockID)[0]; image = document.getElementsByName(imageID)[0]; stateObj = stateMap[block.className]; // 処理 block.className = stateObj.className; // 表示/非表示切り替え image.src = stateObj.img; // 画像の切り替え }
もう一つ修正してもらったのが、obj+"i" の除去だ。これは暗黙のネーミングルールに依存しているのを嫌ったもので、JavaScript、CSS 以外の知識がなければ読めないコードは、できるだけ避けたいからだ。
最終的に if 文がなくなり、上から順にやることを並べただけの単純なコードになったし、意図のはっきりした可読性の高いコードになった。細かい修正ではあるが、巨大なシステムの見通しの良さを維持するためには、こういったことの積み重ねが必要だ。