TDDを実践する中で身につけた「設計に関するスキル」があるなぁと思ったのでメモを残しておくことにする。TDDをやるときのスキルではなく設計をするときのスキル。
染み込んでいる
TDDは以前に書いたように(ってもう7年も前か・・・)あんまり使わなくなっている。でも心の中にある。ウェブアプリケーションエンジニアとしての自分にとても大きな影響を与えている。
TDDから学んだ設計に関するスキル
3つ思い浮かんだ
- まずは動くものを作る
- 必要な分だけ作る
- 「ありえない」の処理を考える
注意
ウェブアプリケーションを書くときのことを考えながら書いている。ライブラリやフレームワークのようないろんなユーザーから利用されるものは、今回の話の対象ではない。
1. まずは動くものを作る
TDDで実装を書くときは「キレイじゃなくてもいいからテストがグリーンになる(成功する)コード」を書く。そして、テストが通る状態をキープしたままキレイにする(リファクタリングする)。テストを書くときも「キレイじゃなくてもいいから確認したいことが確認できるテスト」を書く。それから、テストが通る状態をキープしたままテストコードをキレイにする。
この考え方が自分の設計(実装しながら設計)の進め方に影響を与えている。
最初はキレイとかキレイじゃないとかは気にせずに「動くコード」=「目的を達成するためのコード」を書く。書いている途中で、色んなことが気になったりする。でも、その時点では立ち止まらずに目的を達成するためのコードを書く。色んなことが気になるのはとてもいいことだ。そういう気になったことはメモとして残しておいて後で考える。
動くコードが書けたら、目的を達成するためにいくつか解決しておきたい課題が見つかる。それをひとつずつつぶしていく。課題が全部解決できたらキレイに実装していく。最初に書いた動くコードは捨ててしまって実装しなおすことが多いかな。
こんな風にして動くキレイな最低限のコードを書く。それが終わったら、そこに機能を足していったりメモしておいた気になることに取り組んだりする。「最低限動く」を早めに達成しておいてから、そこにオプショナルなものを足していくように進めると、いつ予想外のことが起こったとしても「最低限動きます」で提供はできる。
「まずは動くものを作る」の中でやっているのは「いちどに相手をするのはひとつだけ」ということかな。ひとつだけに集中して、それを最速で達成するようにしている。
2. 必要な分だけ作る
TDDで実装を進めるときは「目的を達成するために必要な分だけの機能」を実装する。TDDを知る前の自分は「この関数はこういう入力にも対応したほうがいいかもしれない」「こんな風に書いておくと色んな場面で使えて便利かもしれない」「将来的にはこういう機能が必要かもしれない」と、今の時点では必要ない機能を実装してしまっていた。それが、TDDで先にテストを書くと不思議と目的を達成するために必要な機能だけを実装できる。
これも僕の設計(実装しながら設計)の進め方に影響を与えている。
汎用的に作らない。設計をしていたり実装を進めていたりすると、色んな状況に対応できるように作りたくなる。でも、汎用的に作るとアーキテクチャや実装が複雑になってしまう。だから、今必要な機能だけを考えて作る。テストを書こうとすると「今必要な最低限の機能は何か?」と自然に考えるので汎用的に作らずにすんで便利。
早すぎる共通化をしない。なんとなく「こういう機能は共通化することが多いよな」と思っていても必要になるまでは共通化をしない。2つ3つと似たような処理が出てきてから共通化するべきかを考える。そして必要だなと思ったら共通化する。先に共通利用できるような実装にしてしまうより、必要になってから共通実装を考えるほうがちょうどいい実装になる。
今要らないものを作らない。5年後にユーザー数が爆増しても耐えられるようなアーキテクチャで!みたいなことを考えると、とても複雑なアーキテクチャになる。でも、いま目の前で必要なのは少数のユーザーに対応できるアーキテクチャだったりする。そういうときは、今必要なものが何かを考えて、要らないものを作らない。
こんな風に、必要な分だけを作るようにするために、境界を決めてその中で小さく作るようにしている。
エンジニアとしてのスキルは「今必要なものとそうじゃないものの見極めスキル」と「拡張できるように作っておくスキル」かなと思う。必要なものを見誤るとシステムが状況に耐えられなくなってしまうし、拡張できる余地を残しておかないとユーザーが増え始めたときに作り直しになってしまう。
3. 「ありえない」の処理を考える
TDDでは、ありえない入力に対してどう振る舞うのがいいかなーって考えたりする。それと同じことを設計でも考える。
必要な分だけを作る中で「今はありえないんだけど、こういう状況も技術的には考えられるよね・・・」と思い浮かんだりする。だから汎用的に作りたくなってしまうのだけど、それを必要な分だけにするためには、この「ありえない」に対する処理を考えておく必要がある。
「こういう状況ってあります?」って聞いて「あー、ありえないので考えなくていいですよ!」って言われて「了解です!ありえないってことなので、例外を投げてエラー画面を表示しますね」って言うと「え?エラー画面はちょっと・・・いい感じに対応できない?」「ふむ。こういう状況ってありえないんですよね?」「はい!ありえないです!」「じゃ、エラー画面を見ることも・・・ありえないですよね!」「たしかに!んー。じゃそれで」
みたいな話をしたりする。いちばん避けたいのは「ありえない」について設計をしないでいて、将来的に発生してしまったときにシステムが壊れて手に負えなくなることかな。壊れてくれるならまだいいかもしれない。何事もなかったかのように通り抜けて、その先のどこかで何ヶ月か後に意味の分からないエラーとしてでてきてしまう方がつらいかも。
おわり
そんな感じ。ぼーっと書いた。TDDを実践して自分の設計の考え方が広がってたんだなぁって思う。TDDの実践はおすすめです。
厳密な意味でのTDDは最近もあんまりやってないけど、その設計の考え方のエッセンスは僕に影響を与えているー!