牛尾でございます。久々に投稿します。
最近某プロジェクトをお手伝いしているのですが、
お客様のご要望により、私のスーパー苦手で
大嫌いなJavaScriptと格闘することになりました。
そのややこしいJavaScriptプログラムができる過程で
テスト駆動はやっぱりええなぁ〜と思いましたので
ちょっとレポートします。
-------------------------------------------
200X年 それは某プロジェクトで始まった。
主人公たちはUというSEと大型新人(通称大型)
のペアである。彼らは苦手とするJavaScriptと
格闘する羽目になる。
#この物語は、ほぼ本当のことであるが、一部
ストーリを簡略化するためにフィクションが
混じっています。
PJリーダ氏:U君。できたら、メニューって
プルダウン式のやつにできへんかなぁ。
マウス乗せたら垂れ下がるよーな。
U氏 : JavaScriptっすか、、、結構面倒ですね。
PJリーダ氏:お客さんがもともとそれを望んでる
見たい。できたらやってよ。
U氏 :うーむ。しゃーないっすね。。
#全然JavaScriptに強くないU氏はインターネット
から、サンプルを探してきて、内容を読んで
何とかわからんなりに実装する。結構時間が
かかった。
(ま、JavaScriptなんて、よーわからんから、
超嫌いやけど、コピペでええわ。JavaScriptだし)
〜そして、PJ内の計画ゲーム(2人しかしていなが)で、、
お客様:こんな感じだな。でもメニューは3階層まであるん
だよ。だから、垂れ下がってるメニューにマウスのせたら
横に伸びてくれんとね。(さらっと)
U氏 :この機能はJavaScriptで3階層にしたら、結構難しい
んですよ。(だってJavaScriptわからんし、元の
サンプルなんか改造できるような代物ではない、、)
だから、2階層で工夫するとかしたほうがいいかもいれません。
PJリーダ氏:で、マウスを2階層目に乗せたらすぐ、横のメニュー
が出る形式でいいですよね。
U氏 :!!!なんてことを、、、それだったらやるっていってる
見たいなもんやん。
というわけでU氏とオブジェクト指向をいきなり操れる
大型新人氏はいきなりわれわれにとってはスーパー難しい
JavaScriptと格闘することに、、、、
U氏 :おう。大型君。お前JavaScriptって詳しい。
大型 :う〜む。私は大型ですけど、JavaScriptはちょっと、
JavaでもC++でもCORBAでもなんでもやりますけど、、、
U氏 :そうか、じゃどっちも知らんって感じやなぁ。
まぁ、よぉわからんけど、リファレンス読んでやってみるか。
〜土日の空き時間で、U氏はJavaScriptのリファレンスを
読んでくる〜
くそ〜。めんどくさい。
U氏 :(U氏はインターネットで3階層のメニューを探してくるが
今回のPJでそのまま使えるのはなさそうである。)
う〜む。この2階層のやつを3階層にするしかないんか…。
〜今までJavaの開発はテスト駆動で快調だったU氏&大型ペア
は苦しんだ。1日かけても改造ではうまくいかない。〜
U氏 :くそ〜。何でこのわしが、JavaScriptなんざ。こんな時間あったら
超美人ギャルとコンパでもしたいわ。第一こんなだらだらした
ソースはさっぱりわからん。キーー!頭腐る。!
…そういえばJavaScriptってクラスが作れたよなぁ。だれか
コンポジットやテンプレートメソッドまで実装していたな!
しかも、ご丁寧にJSUnitなんてものもあったよなぁ。
こんなん何に使うねんとおもっとったけど、JavaScriptでも
クラス作るなら使えるかも、、、
〜 U氏はJSUnitを使いながら、インターネットを調べて、
JavaScriptで、クラスつくるのを参考にしながら、とりあえず
メニューの項目やメニューをあらわすようなクラスを
コンポジットっぽく作ってみる。ただし、テストができる
ようにと、実際のHTMLのオブジェクトをもっているが、
それに直接操作はしたりはしていない、擬似的なものである。
クラスはできた、さて、本物のHTMLにはめてみると、、
U氏 : うーむ。クラスはできたんやけど、、、はめると結局、HTML
のほんまもんのオブジェクトが絡むと、エラーがどこでおこってる
のかさっぱりわからん。しかも、もとからあるサンプルのソース
はダラダラしていて、改造不能だし、、、
〜 JavaScriptは型が無い言語で、一番厄介なことはテストを書いて
いても、1行ミスすると、すべてのテストケースがすべて動かなく
なるし、どこでどういうミスがあるのかも、ろくにわからない
言語である。
U氏 : ぎゃ〜。なんちゅう言語や!JavaScriptなんて二度とするかボケー!。
(ぶち切れ状態)
〜 最初はJavaScriptだからと、ペアプロしていなかったのだが、
あんまり苦しんでるので、途中から手伝ってきた大型氏は 〜
大型 : Uさん。やっぱ「テスト駆動開発」でするべきちゃいますか?
U氏 : やっぱそうかな。
大型 : やってみます?今から既存のソースをペアプロで追加していきます?
U氏 : (大型がそういってくれたので)冷静になって考えると、
その前に「コードを捨てる勇気」やな。
大型 : なんですか?それ。
U氏 : こーゆーわけわからんようになったときはコードを捨てる勇気を
もつんやわ。つまりこのコードを捨てて1からやるってこと。
大型 : なるほど。
U氏 : しかも、最初は安易にテストできへんと思ってたけど、サンプルの
HTMLを作ったり、そのHTMLのタグにidをつけたりしておくと、
DOMの機能でスタイルとかチェックできるから、テストできるな。
大型 : うーむ。よーわかりませんね。
〜 U氏は覚えたてのJavaScript知識を説明 〜
大型 : なるほど。やっとわかりました。そしたらほとんどテストできますね。
U氏 : じゃ、一応モデリングをざっと考えてみよう。
〜 1階層目と、2階層目と、3階層目の振る舞いが違うので、
ベタにクラスを分けるか、1つのオブジェクトでレベルをもって
対処するかなどを議論して、、
U氏 : ま、普通に考えて、クラスは抽象化して、2種類もっておいて、
違う部分だけをテンプレートメソッド風にしますか。普通やけど、
大型 : そうですね。
〜 実際やるが、なんとJavaScriptはオーバーライドができない 〜
それがいきなりテストで発覚したりした。しかも、継承は、自分
でメソッドをコピーしてやるような感じだ。
U氏 : ダサー。所詮おまけのオブジェクト指向やなぁ。まぁしゃーない。
テストでわかっただけましやな。
〜 そして、継承で作っていたのをやめて、ベタにクラスを2種類書く。
ダサイが言語特性上そうなのだから、無理には継承をしないように
した。しかし、変数の型は無いのでポリモーフィズムは可能だ。〜
大型 : クラスの基本はできましたね。じゃ、次はどんなテスト書きましょ。
U氏 : そうやなぁ。id=menuのタグを探して、その下をDOMで読み込んで
一気にオブジェクトを作らなあかんな。だから、add()メソッド、、
じゃなくて関数をつくららね。ループまわして、addしていけば
簡単にMenu-SubMenu(後は再帰的に、、、)ができるわ。
大型 : それ、ダサダサっすよ。ニャーっていわれますわ。そんなもん、
オブジェクトに親エレメント渡して、再帰的にセットさせたほうが
ええんちゃいます?
U氏 : おっしゃるとおりですな。確かにダサダサ。じゃそっちでいこう。
〜 というわけで、その親エレメント渡して再帰的にセットしてくれる
メソッドのテスト書いて実装 〜。
大型 : じゃ、最初に、テストかいて、、、
menu.setElements(rootElement); 、、、
エラーが出るか確認
U氏 : よっしゃ。messageが見当たりません。って予想どおりでた。
じゃ、クラスにインターフェイスを追加してみよう。
Menu.prototype.setElement = function(element) {
}
おー。テストは通った。
大型 : じゃ、次に、テスト追加
var subMenu21element = document.getElementById('submenu21');
var subMenus = menu.getSubMenus();
assertTrue("エレメントが違います", subMenus[0].getElement()
== subMenu21element);
どうかな。
U氏 : もちろん失敗。予想通り。
大型 : じゃ、実装。こうしてこうして、、、、
U氏 : こうかな。(コードをタイプ)
大型 : OK。テストとおりましたわ。
と、こんな感じで、そのテストケースは終了。
U氏 : うーむ。JavaScriptでもテスト駆動できるもんやなぁ。
あっと、あと、1つのテストケースがグリーンバーになったら
jsファイルやテスト用のhtmlファイルをバックアップしよう。
大型 : なんでですの?
U氏 : さっきの反省やけど、JavaScriptは1箇所間違えたら、
すべてのテストケースが死んでどこが間違ったかわからんように
なるからやねん。
大型 : なるほど。
このような感じでひとつひとつ少しづつではあるが、前進していく。
サンプルを改造して済ませようとおもって、死ぬほど時間がかかって、
ループ状態だったが、着実に進捗してきた感じだ。
そして、金曜日
U氏 : 今日は終了。後はわしが家でやるわ。君に休出はもうしわけないからね。
大型 : いいですよ。
U氏 : いや。今日は終わらなあかん。大体、今日は19:30から巻き系コンパ
や。JavaScriptと巻き系GALはどっちが大切や?
大型 : いうまでもなく巻き系GALです。
コンパを満喫するため、容赦なく仕事を終わらせるU氏と大型氏。
一緒にコンパに参加する営業氏も仕事をほっぽらかしてコンパに来たが
コンパは数年来まれに見る満喫具合で行ってよかった!
U氏 : (家で)さーて残りをやるか。テスト駆動ってると、Javaのときでも
家でもテスト書いてやると、2人より効率はわるけど、着実に進捗
するのがいいよね。
U氏は家で、テストがかける限りのところまで、テスト駆動を続ける。
どうしてもテストがかけないところまできた。
U氏 : よっしゃ。後は無理やからコーディングするか、、、
U氏はテストがすべてかかっているScriptとそれ以外を明確にわかるように
して、コードを書いて、手でテスト。しかし、今まで苦しみに比べたら
意外なぐらいあっさり終了してしまう。やはりほとんどのところを
テスト駆動でいったから、残りの部分はほとんどミスがかけないような
ぐらいのものしか残っていなかった。
U氏 : (大型にメールをして)とうとうJavaScriptメニューできた!!
涙もんや!
大型 : (メールで)おお、月曜にソースみせて勉強させてください。
というわけで、U氏と大型の数日間にわたるJavaScriptとの格闘は終わった。
U氏や大型がJavaScript大嫌いなのはかわりわない。しかし、その格闘を
終えることができたのは「オブジェクト指向」と「テスト駆動」のおかげだった。
しかも、特定のHTMLに依存せず、クラス化しているから、次のプロジェクト
でいわれても再利用できそうである。
テスト駆動があるからこれからJavaScriptでゴリゴリコードを書きたいとは思わない。
でも、テスト駆動、ペアプロにより、意識共有が図れて、いきなり進捗も「手戻り」が
なくなった。「テスト駆動」恐るべし。
たとえそれがJavaScriptであっても。
以上