TDDに関する考察

# TDDの定義
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76353/20b5a5c8-2b4e-abfd-d2a0-5e6276ee9c5a.png)
Test Driven Development
- テスト主導開発：テストが開発プロセスをリードする。 

### 具体的な行動レベルでのTDD概念
テストを先に作って、テストをパスするためのコードを作成すること。
すなわち作る過程で、先にテストを作成し、それをパスするコードを作成することを繰り返すことで正しい動作をするのかについてフィードバックを積極的に受けること

- 普段の開発プロセスではコーディングが終わったときにテストを開始する
    - コーディングが終わった後？　→　エンジニアがコーディングが終わった後、完成だと思う時
    - この順番を変えるのがTDDを適用すること
- TDDを提要した設計
    - 例：生年月日を入力(input)されたら今の歳を出力(output)するプログラム
        - ①はじめは簡単なことをゴールに目指す（生まれた年と、現状の年を入力）
            - 2017, 2020 →　３歳　：まずはこれを作ることを目指す
        - ②作る前に作った後なにをテストするのか設計する。
            - 2017, 2020を入力したら３が出るテストプログラム（今後作って行くプログラムをテストするコードを作成する。
        - ③その後そのテストをパスするプログラム（①をゴールとするコード）を作成
            - 現状の年 - 生まれた年
            - 2020 - 2017
        - ④テストプログラムでこのプログラム（③で作成したコード）を実行する
        - ⑤パスしたら新しいテストを追加する
            - 今回は月まで入力した時に計算するプログラムを作成
    - この作業を繰り返す

### 抽象的なレベルでのTDDの概念
**決定とフィードバックの間に対する認識**、さらに**決定と、フィードバックの間で発生するギャップを調節するためのテクニック**といえる

- [Kent Beck](https://ja.wikipedia.org/wiki/%E3%82%B1%E3%83%B3%E3%83%88%E3%83%BB%E3%83%99%E3%83%83%E3%82%AF)
    - TDDとは？
        - 決定と、フィードバック間に対する認識
        - 決定と、フィードバック間のギャップを調整するためのテクニック
    - TDDはプログラミング技法や、技術的なことより、心理的なものになるかもしれない。
- 決定（Decision)
    - プログラミングを進む中で、「このやり方でやってみようか」「この部分はこのようにやってみようか」などの決定を続けていく
- フィードバック(Feedback)
    - 作成したコードを実行してみると、成功・失敗（エラー）ていうフィードバックを受ける
- この２つ（決定とフィードバック）の間にはギャップが生まれる
    - ギャップが大きくなるほど問題点が多い
    - 自分（コードを書いた本人）がそのギャップを認識しないのが最も問題
    - 上の例文と一緒に説明すると
        - 決定：①をゴールと決めてコードを作成する時「私はこれを引き算で歳を計算しよう」ていうことを決める
        - フィードバック：引き算で計算した時コードをテストコードで実行した結果OK/NGていうプログラム上をフィードバックを受ける
        - この２つの間のギャップを自分が認識してたらTDDをやってると思える

# TDDの効果
## なんでTDDするの？
不確実性が高い時にはフィードバックと協力が大事

- 理由
    - 不確実性が高い時フィードバックと協力を利用すればより良い結果が出る可能性が高い
    - TDDも同じく、フィードバックと協力を高めることなので、不確実性が高い時助けられる

## どんな状況ならTDDしたほうがいい？
- たとえ、どのような部分に対するコーディングを何回でも作った経験があって、結果がどのように出るかはっきり知ってる状態なら、TDDをする理由は特にない
- また、TDDをやったときに得ることが少ないのであれば特にTDDをする理由がない
- だったらどの時するの？？
    - 初めてやってみるプログラム
        - 自分自身に対する不確実性が高い時
    - Clientの要求条件が変わる可能性が高いプログラム
        - 外部的な不確実性が高い時
    - 開発中のコードの変化が頻繁に発生されると判断される時
    - 自分が開発した後、誰が保修するかよくわからない場合
- 結果、不確実性が高い時がTDDを利用するときになる

## 結果どんな効果がある？
フィードバックと協力を一緒に高められる

- フィードバック
    - TDDをするほどフィードバックは増える
        - テストをパスすることで自分のコードがうまくできるのかよく確認できる
        - この部分は人がよく感じられる

- 協力
    - [Kent Beck](https://ja.wikipedia.org/wiki/%E3%82%B1%E3%83%B3%E3%83%88%E3%83%BB%E3%83%99%E3%83%83%E3%82%AF)
        - 'test'は一般的に動詞として使う「テストをする」「テストを行う」
        - たとえ、誰が私に対し生年月日を入力され、現在の歳を出力するプログラムを与えて、テストをしてみろとしたら、私にできるのは数字をいくつか入れて見ることになる
            - 生まれた年と、現状が一緒なら０
            - 生まれた時間がより未来のであれば｀出生前｀
            - などなど
        - ならTDDをすればtestは名詞になる
    - testが名詞になったら？
        - 動詞はその循環すること、名詞（対象、目的語）は後でも所有が可能
        - つまり、Recordとして残れる
        - testが保存できるとは、他の人にテストコードを見せれるし、そのコードを直接実行することも可能
    - なら、TDDがなんで協力を高められるのか
        - testは名詞（対象、目的語）になるとたんこれを共有しやすくなる
        - 共有ができれば協力は自然に高める
            - 他の人が作成したコードを早く理解できる
            - 他の人が作成したコードを簡単に理解できる
            - 勇気ができる（他人のコードを直して、問題があったとしても自動化されたテストが教えてくれるので、心配なく治せる勇気ができる）
                - 私がこのコードを直したけど、問題が出たらどうしよう
                - 私が、これを書いた人の意図を知らずに直してもいいのか…
    - つまりどうしてこのように作ったのかが気になる場合testを共有し、そのコードを見たら理解できる
    - テストコードにはエンジニアの開発過程（何を悩んだのか、どのように決定したのか）などが出るから
    - TDDの定義（決定と、フィードバック間のギャップを認識すること）とともにテストコードを見ると、あの人の意思決定が見えるし、相手はその部分はなんでそのような作り方で作ったのか、理解できるので協力が高められる

# TDDの長所と短所
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76353/5024be3a-7a59-b9b7-2662-f561acd1d059.png)
### なら、TDDはなんでいいのか？
フィードバック、協力を高めることで、不確実性についてすでに準備ができるようにしてくれる。
- 開発スピードが遅くなると思う人が多いため、人々はTDDについて半信半疑する。
    - はじめから２つのコードを作成しなきゃいけない
    - 時々テストをしながら直さなきゃいけない
### TDDのメリット・デメリット
- TDDをすると開発時間が伸びる
    - 開発時間とは？
        - エンジニア自身が、完了したと思うまで機能開発がおわるまで
    - 開発時間がTDDをすることによって10~30%ぐらい増える
- TDDをすると欠陥が下がる
    - 欠陥が1/2 ~ 1/10まで下がる
    - SWを開発しながら予想してない時間がどんどん増えるのはおおよそバグのせいだ
    - TDDをするとこのようなバグの数が下がる
- TDDをするとコードを複雑性が下がる
    - [Entropie](https://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%B3%E3%83%88%E3%83%AD%E3%83%94%E3%83%BC)が下がる
    - Cleanなコードが作成できる
    - 運用コストが下がる
- cf複雑度に関する面白い研究
    - 複雑度について数字で計算ができる
    - Indentが多いコードは複雑なコードだ
    - 複雑度地表(Cyclomatic Complexity)を通じてIndentによって複雑度を数字で計算できる
    - 計算された複雑度が一定数値以上になるとバグを治すときに自らも知らずにバグを入れてしまう可能性は１に収束する
        - すなわち、私がバグを一つ直すためにコードを直したが、私も知らないうちに新しいバグを入れてしまう確率が１に収束すること
    - 複雑度が高いほどバグの数は減らない

# TDDを活用しにくい理由とどうすればうまく行けるのか？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/76353/a6080f19-7924-593b-dd2b-1f68fc0b5806.png)

#### TDDを有効活用するためには？TDDが難しいと思われれる理由は？
- 開発の時間が増える
    - 多い企業は短い間の成果に集中している
    - 全体的な開発スパーンをへらすことより、今日の仕事を終わらさせることを強調するのでTDDの導入が難しい
    - 短期的なものに集中しているので、そのときになったら直せばいい、Clientが怒るといけないから…などの理由で
- TDDは難しい
    - なんで？
        - 今までの開発プロセスと大きくやりかたを変えなきゃいけないから
    - 身についてるのが多いほど変えりにくい
        - Unlearning　：　すでに身につけたものを忘れる過程
    - TDDは開発をあまりやった経験がない人こそ適用しやすい
- **TDDはこのようにしなきゃいけないイメージ／Frameがある**
    - '必ずツール（Unit Test Framework）を使ったこのようにしなきゃいけない'と思ってる
    - このようにルールに縛られるのはAgileではないし、TDDでもない
    - 結局このようなルールに縛られ同じテストをCopy&Pasteしてしまう
    - あまりにもツール／ルールに執着するのでTDDが難しくなるのだ

#### どうすればうまく行けるか？
適応的・進化的に接近しなきゃいけない

- エンジニア自ら「どうすればフィードバックをもっと受けるのか」「どうすれば私がやってる作業について協力がよくできるのか」などを悩みながら自分の仕事のやり方をUpgradeしていく必要がある。
- たとえ、ゲームを開発するとStage3をテストするために
    - いつもStage1,2をClearした後、テストしなきゃいけない
        - テストコストが掛かる
        - どうすればテストコストを下げるのか悩みが必要
    - すでにStage3に行けるようにする
        - フィードバックを手軽く、もっとよく受けられる
        - バックドア−接近方法：テストするたびにどのようなパラメータを入れることで私が望んだシステムのスタート時点へ行くようにする。
    - 重複的にする努力をもっと自動化するようにUpgradeすると、発展ができる