[TDD] TDDってオブジェクト指向を知るためのグッドプラクティスなんじゃないかって話

<br>
### *[アドベントカレンダー 2019年]*
#### *24th December 2019*

さて、もう最終日前日のアドベントカレンダーですよー。
今日は前回までと趣向を変えてTDDについて書いていきます。

\#\# これ、完全に身内用やねんな。
\#\# 外野さんは細かい突っ込みは無しで頼むんやで。
\#\# そのレベル？的な内容から書いてるでな。

※書きたいことが多すぎたので補足ないし追加記事を別の機会に書きます。。
※今回は具体例とか全くなしで突き進んだので、ちょっと後半分かり辛いかも。

## TDDってなんじゃろな

まず、って話。
>
Test : テスト
Driven : 駆動
Development : 開発

テストを駆動しながら開発しよーぜ的な発想です。
駆動とか普段使わない単語なのでイメージ沸き辛いですけどね。

>
駆動：動力を与えて動かすこと。 「前輪－」 「 －輪」
[Weblio/駆動](https://www.weblio.jp/content/%E9%A7%86%E5%8B%95)

全く情報が増えませんねー。
熟語は曖昧に方向は伝わりますが、分かってないと意図が伝わり辛い気がします。。

>
driven : 名詞-driven = "名詞"によって突き動かされた(主導された)
[意訳参考/ネイティブと英語について話したこと](https://talking-english.net/driven/)

ので、英語で見たほうが分かりやすいですかね。

"テスト" によって "主導" された "開発(方式)" 
とでも言えばいいでしょうか。

ここで言う "テスト" と言うのは、大意にして単体テスト的な側面を持つことが多いです。
あくまで、製造される(もしくはされた)プログラムに対する話であり、システム開発全般の進め方の手法ではありません。

また、この単体テストは自動化されたテスト環境(JUnitとかNUnitとか)が必要であり、
本当に昔ながらのShell作っては一個ずつ実際動かして...みたいな環境は想定していません。
※だって、ケースはまだしも手動テストを先に作るとか、時間に対する矛盾の塊みたいなものですし。

従って、TDDとは単体テストの自動化が行われた環境上にて、
その自動化されたテストによって主導される開発手法と言えるでしょう。

## まぁ、情報は増えてないんですけど

定義を書いたからといって、結局 "主導" ってなによって話ですよね。

(若手向けに書いているので)
まずは自分がコードを書くときにどう言う順番で思考するか考えてみてください。

作るものを設計書で知って、そのまま作ってみて、
抜けがないか確認して、実際動かして...って感じで作っていませんか？

それ自体は非常に正しいことです。
私の経験ではプログラム1行レベルまで詳細設計書に記載されていることもありましたし、
それ以前に設計書と違う構造にしてしまったらそれは正しく動いたとしても "バグ" なのですから。

しかし、そのとき製造者は何を中心に考えているのでしょうか。

おそらくですが、作ること、を中心に考えている人も多いのではないかと思います。
そのとき貴方は "作ることに主導された" と言えるでしょう。

これを上記した "テストに主導された" 場合はどうなるのかと言うと、

作るものを設計書で知って、そう有るべき為のテストを作ってみて、
実際にそのテストをクリアできるように作ってみて、クリアできることを確認して...

って感じになります。

先に "そう有るべき為のテスト" を作るって何だよってなりますよね。

## "そう有るべき"
コードには必ず役割があります。

この処理はデータにアクセスする、この処理は取得したデータから計算するなど、
全てのコードは "こういう事をするため" と言う目的があります。

そして、"こういう事をするため" の処理を連結することで "結局こういう事がしたい" と言う最終目的に繋がります。

(順番としては"こういう事がしたい" だから "こういう事をする" と言うブレークダウンになりますし、それを設計フェーズでするのですけどね。)

この "こういう事をするため" の処理に対して、結果的に "こうなっていればやりたい事が出来てる" 事を確認するのがテストである、と言えます。

「Aと入力したら色々計算してBを出力するための処理」では
「Aと入力したらBが出力されるべき」だし「Aと入力したらCやDは出力されないべき」である、
こう言った "そう有るべき"　ことを確認するのがテストである、と言うことです。

この “そう有るべき” ことは分かってるし、
先に確認すべきことはラインナップしちゃおーぜって考え方がTDDの端的な目的です。

## なんでわざわざ逆に作るの？

もちろん逆に作ることは非常に面倒ですし、
後述しますが作るコードの量も純粋に増えます。
分かり辛くて作業も増えると、これだけ見ると全く良いとこなしのTDDですが、
それでも考え方として根付いているのはメリットも大きいと言うことです。

さて、ではTDDの何が便利なのでしょうか。
一般的には以下の3点がメリットとして挙げられます。
>
1. 要件への理解を深めてから製造を実施できる。
2. バグが少なくなる。
3. デバッグの時間が少なくなる。

要件が分かっていなければ "そう有るべき" ゴールは見つけられませんし、
"そう有るべき" テストをクリアできるようになればバグも少なくなり、
結果として、デバッグに使う時間も削減できます。

TDDは結論を準備しておくことで、
そこに帰結させることによりあらゆる過程を効率化することを目的とします。

とは言っても、前述の通りテストを事前に作るのでコードの量や手間も大きく増えます。
製造が完了するまでの時間は正面から作りに行くよりも大きく取られます。

本来はその分、コードを書くときの手間を減らさなくてはいけません。
テストを含めて本来より2倍の量を作るなら、本来のコードを1/2まで減らして初めて価値が出るとも言われています。

もちろん最初からそれだけのことが出来るわけはありませんし、
出来るならスタンダードな考え方として教本にも最初から書かれているでしょう。

実際には最初にテストを準備したとしても一点の漏れなくケースを書くことは至難の業ですし、
また本当に漏れなく書いたとしたら2倍どころではなく何倍もの時間を使う事になります。

最初に意味を成す程度のテストを準備し、それに添う形でコードを作り、その中で出てきた問題に応じてテストを修正し、
それに適うコードを追加することで "テストに主導された" 開発手法として成り立ちます。
書くまでもないことですが、これには一定以上の仕様理解、コーディング技術、チームでの共通理解、レベル感の統一など非常に多くのハードルが存在します。

それらが完璧に噛み合ったときに効果を初めて発揮すると言われているのがTDDです。

## それでも尚、TDDを知るべきだと思う理由

それだけハードルが高いため、中々効果的にTDDを導入できるチームは多くありません。
そしてまた、私もTDDを実際にやろうと言う意味でこの記事を書いた訳ではないのです。

私はここ数年で何人かにjavaを教える機会に恵まれましたし、
他にも社内でコーディングの話をする機会がとても増えました。
以前は5人程度しかいなかったPGも今は2,30人ほどになり、色々な言語を扱うメンバーが出てきました。

オブジェクト指向の人たちだけではありませんが、
それでも僕は開発者である以上オブジェクト指向も知っておいて欲しいと思う訳です。

極論しますが、そのオブジェクト指向を勉強する、
もしくはオブジェクト指向的なコーディングを練習する際にTDD的な思考回路は非常に有用だと考えています。

あくまで一側面での話とはなりますが、以下は物を作る思考回路を作っていくと言う段階の話として読んで欲しいです。

先に答えを用意するためには仕様の切り分けが必要であり、
無理のないテストを作るためにはクラスやメソッドをしっかりと細分化する必要があります。

先にテストを作るためにはどうするか考え続けることで、
過度なオブジェクトを取り扱わなくて済むようにクラスやメソッドの肥大化を抑えることが出来、
逆に手間を掛け過ぎる事を厭うことで無意味なレベルまで細分化しなくなるでしょう。

その時、何のためにそのコードの塊を作ったのか、どんな役割を持たせたのか、
その役割は "どう有るべき" なのか。

オブジェクトとして明確に役割を決めていなければ、結論を事前に準備することは非常に難しいですし、
決めてさえいればその為に必要なことは何かと言う条件をテストに書いていくだけで事足ります。

それらを自分の言葉で説明できるようにコードを組むことが出来るようになれば、
オブジェクト指向的なコードを勉強する一助にはなると私は思います。

私自身もオブジェクト指向をマスターしているとは言えないでしょうが、
それでも自分がオブジェクト指向を理解し始めたのはTDDに出会った時だったと思います。
(※マスターしたとか、ｼｼｮｰも見てるかもしれないQiitaで言えないよね( ´・∀・)(・∀・｀ )ﾈｰ)

別にチームで実践するレベルまでTDDを持っていく必要は必ずしもありません。(やりたいですが。)
現在では欠陥も多く指摘され、BDDなど新しい(？)手法も編み出されてきています。
ですが、これからプログラミングを学ぶ人達には是非オブジェクト指向を理解する一端として、
TDDの考え方を知って欲しいと一人で思っています。

コードを書く時に自分の中でこのクラス/メソッドは何のために作るのか、
"そう有るべき" 姿は何なのか問いかけ続けてください。
もし将来TDDするまでもなくTDDしていたとなれたら、
きっと物を作ることを手段にして価値を作ることが出来るようになると僕は思います。

もう少し具体例を交えながら説明したいのですがあまりにも長大になってしまうので、
今回は僕の中で長年燻っていた、オブジェクト指向に対する概念的な憧れだけを乱筆して終わりにしようと思います。
<br><br>
とっぴんぱらりのぷう