TDD勉強会主催レポート inspired by TDDyyx

# はじめに
この記事は、[LIGHTzアドベントカレンダー2021](https://qiita.com/advent-calendar/2021/lightz)の３日目の記事です。

@KTasknこと、たすく、です。
LIGHTzは業務に支障がでない範囲で自由な働き方ができる風土が整っています。
私は現在、そんな弊社で働きながら大学院の修士１回生として、データサイエンス・コンピュータビジョンの研究に励んでいます。そんな大学院生活、まわりの同級生と輪講や勉強会を開く機会もあったりするのですが、そのなかで私が主催したTDDの勉強会についてどのようなことを行ったのかレポートしたいと思います。

また、今回紹介するTDD勉強会は[TDDワイワイ会](https://tddyyx.github.io/)の[@2018年9月沖縄](https://tddyyx.connpass.com/event/95218/)に私自身が参加した際に感銘をうけインスパイアしたものになります。


# TDD勉強会　（テスト駆動開発）プロットとレポート
## イントロ
### テスト書いてないとかお前それ@t_wadaの前でも同じこと言えんの？
このセンテンスは日本のTDDの"HelloWrold"なので、どうしても必ず先頭におかないといけない

### 割り算をするメソッドを書けますか？

```python
def divide(numerator, denominator):
    return numerator / denominator
```

プログラミングに入門してある程度期間が経った方なら、上記のようなコードを書くことはそう難しくないだろう。

### では、さきほどのプログラムに含まれるバグをいくつ挙げられますか？

。。。と聞かれると、こなれたプログラマも一瞬考えてしまうかもしれない。

* denominator = 0
* numerator、denominatorが数値ではない
* numerator、denominatorがNone
* numerator、denominatorともに整数型だと、思った動作にならないかもしれない
* etc..

と、たった２行のコードにも多くのバグが埋まっている。
なので、多くの場合、動作確認をしてバグを埋め込まないようにする。

1. 機能や修正案を思いつく
1. コードを書く
1. 動作確認をする
1. うごいた！、やったね！

### しかし、大抵、そうはうまくいかない
多くの場合、上記の４ステップだと実際には、以前動いていた機能が動かなくなったりする。

1. 機能や修正案を思いつく
1. コードを書く
1. 動作確認をする
1. うごいた！、やったね！
1. **以前は動いていた機能が動かない**
1. **以前は動いていた機能も動作確認をする(何個あるの？)**

自分のための小さなプログラムなら、上記の方法でまだ間に合うケースはある。
ただし、世の中の仕事としてのプログラムは残念ながら違うのである

### 仕事のプログラミング

* 自分がn年前に書いたコード
* 他人が書いたコード
* どこの誰かが書いたかもわからないコード
  * （大抵は数年前に会社を辞めた名前だけ知っている人・・）

### 仕事のプログラミングの悲しい話
残念ながら多くのプログラミングの現場では、
**すでにリリースされたコードは、たとえロジック上バグが見つかっても、よりエレガントなコードを考えついても、バグが起きるまで絶対に修正しない、させてくれない**
なぜなら
**修正したらそれ以外の数百個〜数千個の機能も動作確認が必要になるからである**

悲しい、ほんとに悲しい。

では、どうすればよいのだろうか？

## 自動テスト
プログラマなのだから、動作確認もプログラムで行えばいいのである。
さきほどのコードをテストするのであれば、下記のようなコードとなる。



``` python
def test_divide():
    # もしdivideがうまく機能しなければ
    # assertでエラーがでる
    assert divide(1.0, 2.0) == 0.5
    assert divide(3.0, -2.0) == -1.5
    assert divide(0.0, 1.0) == 0.0
    with pytest.raises(Exception):
         divide(1.0, 0.0)
```


## じゃあ、いつテストを書くか

### テストとは仕様を確認するものである
### コードより先に仕様がある（当然）
### つまりテストはコードより先にある

### テストはコードを書く前に書こう！

## TDD

### TDDの手順

1. 目標を考える
1. 目標を示すテストを書く
1. テストを実行し、失敗させる（Red）
1. 目的のコードを書く
1. テストを成功させる（Green）
1. Greenを維持しながらリファクタリングを実行する
1. 1.に戻る


### TDDを実践すると

1. 機能や修正案を思いつく
1. **テストを書く**
1. コードを書く
1. ~~動作確認をする~~
1. うごいた！、やったね！
1. ~~以前は動いていた機能が動かない~~
1. ~~以前は動いていた機能も動作確認をする(何個あるの？)~~


# TDDハンズオン

[cyber-dojo](https://cyber-dojo.org/creator/home)を使うと、ブラウザからTDDのハンズオンが簡単にできる

## ハンズオンのルール

* 好きな言語とテストフレームワークを選ぶ
* [FizzBuzz](https://ja.wikipedia.org/wiki/Fizz_Buzz)をTDDで作成する
  * **3の倍数はFizz、5の倍数はBuzzになる**
  * つまり世界のナベアツである
      * （院生には通じたが学部生には通じないかもしれない）
* 2~3人で１つのPCを使いモブプログラミングをする

## ハンズオンにおける指針

* 1~3回の機能を作り終えたタイミングでコードを書く人（オペレータ）を交換する
    * オペレータ以外がリードすることを意識する（メンバーがおいてきぼりになるのを防ぐ）
* **コードを書くときは、コンパイラ/インタプリタの言うことだけを実装する**
    * スモールステップでテストとコードを書く
    * テストを書くときはコードを意識しすぎてはいけない
* バグを埋め込むと夜中に呼び出されるという気持ちになってテストを書く
    * 自然とテストケースが増えていく

テストコードを書いたことないは最初はとまどうので、下記のようなコードからスタートする
また、**FizzBuzzで扱う数字は自然数なのでテストを書くことに慣れていない場合は、0やマイナス、浮動小数をテストすべきことに気づかない場合があるので、適宜突っ込む**、また、**0やマイナスなどの値が与えられたときの挙動はチーム内で合意した仕様にする**

``` python
import fizzbuzz
def test_fizz():
    assert fizzbuzz.fizz() == 0
```

## レビュー
2〜3チームでやると、FizzBuzzという簡単な問題なのに、各チーム全く異なるテストとコードが出来上がる。（とくに学生は他人のコードを見る機会が少ないので）、互いにレビューすると発見が多くある。

## おわりに
レポートというよりもプロットがメインとなりましたが、こんな感じで、今後もTDDを広めるイベントを自分でも主催していきたいと思っています