Ruby on Railsで作られたとあるWEBサイトの運営に携わっているわけであるけれども、やはり趣味で作るプログラムなんかとは開発の流れが違う。
いわゆるTDD(TDNじゃないよ。DBは出てくるけど)というやつだと思うんだけれども、「テスト」というのが開発サイクルにおいて確固たる地位を築いている。
趣味でPython使って作ってきたプログラムなんかは、頭に入っている仕様に基づいてコーディング中、適当にprint文を入れておいて途中まで実行して期待してる振る舞いをしてるかな?と確かめるのがテストだった。あとは各スクリプトのmainに少しテスト用のコードを入れてみたり。で、全部出来上がったらprint文を消して完成~と。
つまりテストはやらなければいけないことではなく、別にしなくてもいいんだけどやったほうが自分にとってわかりやすいからするものであった。
しかし、Railsのほうではテストが超大事。テストといいつつ、仕様書も兼ねているのだ。
もちろん仕様自体はチームの誰かが考えるんだけれども、その後チーム全員に仕様を共有する際は仕様のほうが優先される。「自分はそういうつもりじゃなかった」のなら、テストをそう書いておけ、という話になる。
なのでテストはすべてのメソッドに対して「このメソッドはこういう状況の時にはこういう値を返す」というのを全部明文化している。ヘタすればテストコードのほうがテスト対象より長いんじゃないか?というくらい。
(ちなみにテストにはRSpecというのを使うのだけれども、これがまた特殊なキーワードが多くて最初は面食らった。どうも自然言語っぽくかけることを志向しているそうなのだが、なんかSQLっぽくてあんまり好きじゃない…)
ソッチのほうにはまったく関わっていないので詳細は不明だけれども、modelのコードだけを直してGithubでプルリクエストを出したところ、自動的にテストを実行して「おいコラァ!降りろ!テストしてんのかコラ!…」というメッセージを送ってくるやつがいた。
人を小馬鹿にしたような目つきがいやらしい |
(TraviCIという名前。継続インテグレーションツールというものらしい。)
書かれたコードをデプロイするする工程はほとんど自動化されているようで、その際にこのコードは反映してもいいのか?というのはテストを通っているかどうかによって決められているということである。
要するにテストが王様なのである。
当初そんなにテストしてることすらろくに知らなかったので、このコードが正しく動いているかをどう示すか、なんて露ほども考えていなかった。なのでいざテストを書かなければならないとなった時にどうにもこうにもできないコードを書いてしまっていた。
要するにひとつのメソッドに処理を詰め込んでいた。
そこで言われたのが、「テストしやすいコードは他の人が読んでも挙動がわかりやすいコードになり、良いコードになる」ということ。まぁ考えてみれば当たり前なのだが、非常に重要なことである。
テストは入力に対する出力のテストであって、状態まで監視しているわけではない。テスト対象が何をしているかは知らないけれども、投げた入力に対して期待通りの結果を返すのならばOKとみなすというものである。
ということは、ひとつのテスト単位の内部で問題が起きた時に、そのどこで問題が起きてるのかまでは教えてくれないのである。なのでひとつのテスト単位が延々続いていると、問題が起きていることはわかっても結局デバッグは力技になってしまう。コードを書いた本人ならまだしも、そうでなければその延々続いているコードを全部読み解かなくてはいけない。
一方、きちんと処理を分割できていれば、問題が起きている小さなブロックだけに注目すればすむ。バグを探すのも簡単だ。
しかもその他の部分については、そのメソッドが内部的に何を行っているかは知らなくてもよい。そのメソッドはテストを通っているんだから正しい処理を行っているとみなすことができる。つまり、そのメソッドが問題を起こす/改善が必要になるまでは内部まで知っておく必要はなく、定性的にどんなことをするメソッドなのかを知っておくだけでよい。
「良いコードとはどんなコードか」ということはなんとなく聞いているけれども「良いコードを書くには何を心がければよいか」というのはまったくもって考えていなかった。
今後は実際にテストを書くかどうかは別にして、「この部分をテストをするならどうやってテストするか」がすぐ思い浮かぶような単位に処理を分割していくようにしていこうと思う。