デスマの中でもTDDを貫いた話

### いきさつ

CDO「時間がないを言い訳にTDDが浸透しない」
俺「テスト・ファーストでないと実装できない体にしちゃえば、時間がなくてもやりますって」
CDO「それ、社内LTでしゃべって」

前世紀末「XP入門」のままのTDD原人のLT資料です。
※俺の環境：Java/JUnit/Eclipse/Gitlab

----
### ネタ本

ケント・ベック
[「XP エクストリーム・プログラミング入門
 ソフトウェア開発の究極の手法」](https://www.amazon.co.jp/XP%E3%82%A8%E3%82%AF%E3%82%B9%E3%83%88%E3%83%AA%E3%83%BC%E3%83%A0%E3%83%BB%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E5%85%A5%E9%96%80%E2%80%95%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E9%96%8B%E7%99%BA%E3%81%AE%E7%A9%B6%E6%A5%B5%E3%81%AE%E6%89%8B%E6%B3%95-%E3%82%B1%E3%83%B3%E3%83%88-%E3%83%99%E3%83%83%E3%82%AF/dp/489471275X)
和訳初版 2000/12　**古い!**

----
### Test First

実装コードを書いて、そのテストをする
その順番をひっくり返す

----
### １ 今書ける**一番簡単なTestCaseを一つ**書く

- Dao の CRUD なら Create から
- 最初は実装もinterfaceもないから、compileもできない
- 当然のことなので敗北感はない

----
### ２ IDE の quick fix で空classや空method作る

 - compile できた
 - それだけで **なんか達成感** :smirk:
 - IDEに感謝。プログラマ黄金時代©Matz

----
### ３ Run Test - Red!

compile できたらすぐ Run Test.

 - 実装の中身なし Test Fail :broken_heart:
 - 当然のことなので敗北感はない

----
### ４ クソコード実装

最速最短でテストを通すためのクソコード実装

許す!

 - 即値のハードコーディング
 - コピペ
 - etc :poop:

----
### ５ Run Test - Green!

- 最速最短でテストAll Green :green_heart:
- なんて**全能感** :smile:

----
### ６ local git に commit

- TestCase １つ
- それを満足する最速最短実装コード
- そして 1に戻る

----
### テスト・ファーストまとめ

1. 一番簡単なTestCaseをひとつ
2. 空class, 空method
3. Run Test - Red! :broken_heart:
4. クソコード実装
5. Run Test - Green! :green_heart:
6. local git に commit して 1へ戻る

----
### ドーパミンサイクル

メンタルに良い。

- Redになっても敗北感なし
- Greenになるたび達成感・全能感
- 回転するたび**脳内麻薬どんどん出ますよ** :muscle:

----
### 「条件付け」

- 実装が空で Run Testは無駄？
- Red->Green でドーパミンを出す「条件付け」
 - 一度Redにしておく
- Testをコピペしたまま手を入れ忘れて、いきなり Green というのもたまによくある話

----
### JUnit画面でドーパミン　変態？

「条件付け」で自分の脳を改造する

- Green画面 → 人生で最高の記憶を開く
- 繰り返すうちに記憶操作を意識しなくてもテンション上がる
- Plugin もあるかも
 - Green画面 → お気に入り画像がpop-upする
 - なければ作りなよ

----
### だんだん簡単じゃなくなる？

- **前回のドーパミンを燃料に**ブン回して**さらに大きな達成感・全能感**を
- ドーパミン・サイクル　良循環
- TestClassのコードも組み合わせ可能なストックが蓄積していく

----
### TestCaseレビュー

- 推奨：サイクルをブン回して、一通り(ある程度）揃ったら、Testレビュー
 - WIP(Work In Progress)の　Merge Request
- 仕様理解が正しいか確認してから次のステップに
- 実装のソースコードレビューはまだ先
 - 今はクソコードの山

----
### リファクタリング

Testレビュー後、クソコードの山の実装を洗練

- レビュー済みTestCase/TestCodeはFix。
- 機能の等価性を保ったまま改修＝リファクタリング
- デグレ・リスク回避

----
### １ 一番簡単なRefactoring

**一番簡単**に「よりましな」実装コードにできることを**1つだけ修正**する

IDE の refactoring 機能で機械的に修正するのも１つ

---
### よりましなコード

- コーデイング規約
 - 最速最短コードとコーディング規約準拠は両立が◎
- DRY原則（Don't repeat yourself）
- リーダブルコード
- アンチパターンにはまってないか

----
### ２ Run Test

- Green? :green_heart:
 - 一番簡単なところだったのでたぶんGreen。
 - **それだけでなんか達成感** :smile:
 - local git に commit して １ に戻る

----
### ３ Test Red - Debug

- Red? :broken_heart:
 - **なんで？敗北感** :cold_sweat:
- Debug
  - 1カ所だけの変更。簡単に原因はわかる
  - Greenに回復したら**全能感** :smile:
  - 手をつけちゃいけないやつだったら、元に戻して１へ

----
### リファクタリングまとめ

- 正しいTestCaseが一揃い
- 作業の方向性の正しさを確信
- 1サイクル回すたびにコードが綺麗になる
- **脳内麻薬どんどん出ますよ。** :muscle:
- 予定工数を消化したら打ち切り
- remote に push してCIへ

----
### CI　継続的インテグレーション

1. 開発branchにpush
1. Jenkins で全体統合テスト
1. All Green なら本流へのmerge request
2. ソースコードレビュー

----
### Don't say "lazy"

テスト・ファーストは、遅くないよね？

- 初期は最速最短のクソコード
- 予定工数内で可能な限りのリファクタリング
- リファクタリング時間=0でも、要件を満たす実装は手中
- CI通してればクソコードの山のままリリースする判断も可

----
### 中間まとめ

「テスト・ファーストでないと実装できない体」
　＝脳内麻薬どんどん出してテスト中毒になったプログラマ

「軽い気持ちでいっぺん試してみなよ。みんなもやってるし。」:syringe::pill:

----
### TDDの補足

元ネタがXP、エクストリームなので、いうことがいちいち極端です。

- 今書ける（主観で）一番簡単なTestCase
- （主観で） 最速最短でテストを通す
- （主観で） 一番簡単に「よりましな」実装コードにできる

何から手をつけるか、どこまでリファクタリングするか、実際には高度な判断をしてください。
似たようなレベルだから手当たり次第にやることもあります。判断コストも含めての「一番簡単」

----
### 2013-01 某デスマのロードマップ

- 2012-11-20 サービスイン
- 2013-01-xx 初回請求
- 2013-02-01 全額返金以外の通常退会、コンビニ払い
- 2013-02-21 新規Web機能リリース
 - 「新機能は、お客様のご利用データが十分蓄積されてからのご提供となります。」
- 2013-04-01 サービス仕様大改訂と同時に年度切替

----
### ブリーフィング　

2013年1月から参加

- サーバーのbacklogを一掃して
 - 契約系にうつる前任者の担当分
- backlog はどこで管理している?
 - Redmine は個人レベル、プロジェクト運用なし
 - 口頭ベース
- サービス外部仕様書 2012-07-02 こんなに古くて大丈夫か
 - 仕様書はもうついていってない。現物みながら

----
### はじめの一歩

```
Checkout & Build
r14105 (12/28 09:59)
JUnit Runs:602
14:19 JUnit開始
15:22 終了 Errors:64 Failures:8
```

TDD原人は、project取得したらすぐに Run JUnit。

----
### なんじゃこりゃ

- 1h以上かかるだと!
- 10%も Error
- ひえー :scream:

----
### 状況把握

- 実装javaに較べて`*Test.java`が古すぎ
 - 最初は UnitTestを書いていたがメンテやめた？
- AllTests.java の TestSuite発見
 - `Runs: 171/171 Erros:15 Failures:0` 所要時間20分
 - Error率は似たようなものだが、すべてが `mail smtp`
 - dummy の smtpサーバを教えてもらってAll Green
 - 生きているTestClassはこのSuite/SubSuiteで管理中

前任者の負担を小さく、**プロジェクト状況をJUnitに聞く**

----
### CI欲しい

- Run JUnit に20分以上　ローカルで毎回全部はリズムが悪い。
- 特定の branch名を取得してテストを回し続ける環境が欲しい。
- 所要時間の大半は、外部顧客管理サービスのレスポンス待ち。
 - それなら、マシン性能は低くても、所要時間に影響しない。
- 仮想環境に、PostgreSQLと、smtp4dev入れて、Jenkins用branch にコミットしたら、自動テスト起動にしよう

----
### CI環境構築

- 2013-01-07 15:00 構築開始
- 2013-01-09 10:41 JenkinsTest Green

新参者が**やらかしてもこれで検出**される。**安心感**。

----
### DBリバースエンジニアリング

実装担当の負担を小さく、**DB状況をSchemaSpyに聞く**。

- スキーマ定義から自動でhtml形式のER図
- http://schemaspy.sourceforge.net/

----
### JUnit Debugで実装把握

生きているTestCaseをDebug実行して、内部実装を把握

- 少しでもUnitTestがあったので、橋頭堡にして信頼できるところを広げていけた

当時の作業メモ

- なんと BaseDao.java を使っていない。
- 上記テストを実行しても BaseDao.java の factory では停止しない。
- BaseDao.javaは 古いUnitTestのごく一部でしか使っていないということらしい。

----
### Redmineプロジェクト管理

- サーバータスクのRedmineチケット運用 2013/01/22～
- 2013-02-01分 からRedmineロードマップで Todo管理

----
### 四半期評価 実績

- 2/21 に新Web機能を追加対応込みで予定通りリリース。
- 3/29 のサービス仕様大改訂を予定通りリリース。
 - 改訂内容は、当初企画案のMax以上まで実装
 - データマイグレーションで改訂前の蓄積データを扱うときも、ロジックの2本立てを回避

----
### 四半期評価 直属上司

- 顧客側決裁権限者に商品をアピールできる機能にできた。
- ○○自動選択の実現など当初の計画にはなかった機能も実現し、施策の効果を最大化した。
- 平行してテストケースの作成も推進して頂き、今後の保守・メンテナンスコストの削減に貢献した。

追加要件も全部呑んでミッション・コンプリートです。

----
### 某プロダクト2016状況

- 2013: `Runs: 171/171 Erros:15 Failures:0` 所要時間20分
- 現在: 3,009個のテスト 所要時間47分
 - TestSuite管理はやめた。原則全部のTest.classがCIで走る
 - JavaScript も jasmine でTest. いくつあるんだ?

----
### TDDの敵：状況依存

 - 特定の日時でないとテストできないケース
  - [現在時刻が関わるテストから、テスト容易性設計を学ぶ by t_wada](https://codeiq.jp/magazine/2013/11/1475/)
 - 特定のDB状況を前提にしないとテストできない
  - 例：あるTABLEの1年間の履歴から、次のアクションを決める
  - 対策1:setUp() の TestDataRegister()を頑張る
  - 対策2:フラグを立てるロジックとフラグを見て動くロジックに分離
  - 対策0:テストしにくい要件を、企画段階でDropして KISS(Keep It Simple, Sxxxxx)原則を貫く
 - Multi-Thread Timing

----
### TDDの敵：遅い実装

 - ドーパミンサイクルの回転数が落ちる
 - 某プロダクトだと、外部連携顧客管理サービスのレスポンス待ち
  - 2013/07/24 Mock化
 - Springの動的Binding
  - 未解決

----
### TDDの敵：必要のないテスト

 - ドーパミンサイクルの回転数が落ちる
 - 例： 該当者がいない古いタイプの契約のテストケース
 - 例： 境界条件でもないのに、無闇にパラメータ値のバリエーションでTestCase増やしている

----
### TDDの敵：Test Red で帰る人

「明日朝自分が死ぬかもしれないと思ってpushしなさい」

----
### TDDの敵：ラスボス

- 実装を軽くみる風潮
 - 「機能設計だけして、実装は委託して。君は単価高いんだから」
 - 不倶戴天

----
### 最後に

- CDOと各技術大臣はTDDの味方です。
- ネタ本もトーカも古いので、最新情報はTDDBootCampとか外部リソースで追いかけて