半年でテストカバレッジを69%→81%まで上げたけど重要なのは技術力ではなかった話

# :pencil2:はじめに
自分が勤めてる会社でテストカバレッジを上げるプロジェクトをリーダーとして始めて
サーバーサイドメンバーのべ15人で約半年で69%だったテストカバレッジを81.8%まで上げることができたのでその時に意識していたことや、やり方についての備忘録として残しておきます

ちなみに全体としては69%→81.8%ですが

個別でみると下記のようになってます

|  ディレクトリ  |  カバレッジ上げ前  |  カバレッジ上げ後  |
| ---- | ---- |---- |
|  controller  |  77.7%  | 94.9%  |
|  service  |  81.3%  | 95.4% |
|  domain  |  85.7%  | 98.2%  |
|  model  |  78.8%  |98.4%  |

# :pushpin:アジェンダ
- テストカバレッジを上げる施策をやって良かったことは？
- 参考になる人ならない人
- 最初にやった方がいいことは？
- どうやってルールを決めた？
- やってる中で起こった課題は？
- 失敗するとしたらなぜ失敗するか？

# :thumbsup_tone1:テストカバレッジを上げる施策をやって良かったことは？
そもそもテストコードを書くことでどんないいことがあるのでしょうか？
一般的にテストコードを書くといいと言われてることはもちろんですが僕個人が実際にやってみてメリットだと思ったことをいくつか紹介します。
## 個人的に良かったと思うこと

- **成果として言いやすい**
    - 定量的に伝えられるので　「できた」「できなかった」　がはっきりと出ますし、そこそこいい成果となればこうやって記事にもできるわけですし、「〇〇という機能の〇〇という箇所の修正を行なった」というよりも**明確で分かりやすい**です。
   
- **テストの知見がめちゃめちゃ広がった**
    - テストのルール決め、課題に対しての対応策を考える、上長との目標すり合わせなどでテストについての知識を広げないと議論できなかったりすることがかなりたくさんあったので知見は広がったかなと思います。

## チーム全体として良かったと思うこと
- **やっぱりテストがあると安心感が違う**
    - リファクタをしよう！と思いやすくなる
- **そもそも使ってないコード、バグなどを見つけることができる**
    - ユーザークリティカルなものはほとんどなかったですが、明らかに**意図している動作とは違っていたり**、**仕様と実装が合っていなかったり**と、見つけれるところは多かったです
- **チーム全体で全てのコードを見るので課題を見つけやすい**
    - **課題が無い**と**改善**もできませんまずは課題を認識するところから！

# :information_desk_person_tone2:参考になる人ならない人
良かったことは結構いろいろありますが、、、
もしあなたもカバレッジをあげようとしてこの記事を見ている場合は下記3つのような条件が当てはまるような組織でないと機能させることが難しいと思います。
もし3つのうち1つでも当てはまらないところがある場合はそれらの醸成を先に行う必要があるかと思います。

1. **メンバー全体でテストを書く重要性を理解をしている人がマジョリティであること**

2. **タスクを振り分けるリーダーがテストの重要性を理解し改善するべきであると感じていること**
3. **自分がテストを一番書いて、誰よりもコミットするぞ！という強い気持ち**

## メンバー全体でテストを書く重要性を理解をしている人がマジョリティであること

そもそもこのプロジェクトは

「**重要だけど緊急度が低い**」タスクちゃんとやろうぜ！

というのが前提となっているのでそもそもの**重要度が高い**という共通認識が少ない場合はやらされ仕事となりすぎてしまいメンバーのモチベーションなどが続かない可能性が低いです。

## タスクを振り分けるリーダーがテストの重要性を理解し改善するべきであると感じていること

どんなにメンバーがテストのことを重要と考えていてテストカバレッジを上げたい！と思っていても、どこにどれくらい時間を使うことを振り分けることのできる**リーダーがテストの重要度を認知していない場合**、テストに割ける工数は日に日に減っていきます。

なんなら**重要性を理解しているリーダーであってもテストの工数は削減されがち**です。

仕事としてコードを書いている以上**施策開発に多くの時間をかけることはビジネス上当たり前**で、目先の成果を考えれば**テストの優先度が低くなるのは必然**です。そのことを入念に理解しましょう。

## 自分がテストを一番書いて、誰よりもコミットするぞ！という強い気持ち

結局これが**一番重要**かもしれません。
- プロジェクト大きいほどテストカバレッジを1％上げるだけでも大量のテストコードを書かなければいけない
    - **成果が見えるスピードが遅い**
- 多くの場合でテストコードを書くことは**技術的成長につながらず、つまらないと思われていること**
    - 本当はテストの考え方や手法はかなり奥深く勉強できることはたくさんある
- メインのタスクの優先度に負けて**停滞・中断を余儀なくされる**ことが往々にしてある

これらの困難に打ち勝たなければこのプロジェクトを最後までやり切ることは難しいです。

# :muscle:最初にやった方がいいことは？
1. 計測する

2. 全体像を把握（タスクに落とし込む）

3. リーダーと目標のすり合わせを行う

4. メンバーに打診する

5. 定期的に進捗を共有する会を作る

## 計測する

まずは計測しましょう。

**「推測するな、計測せよ」**

という言葉はあまりにも有名ですが、これができないと何も始まりません。
テストカバレッジを測定しログとして残してくれるツールはいくらでもあります
- [codecov](https://about.codecov.io/)
- [coveralls](https://coveralls.io/)
- [sonarcloud](https://www.sonarsource.com/products/sonarcloud/)

どれを使ってもいいですし、なんなら自作してしまってもいいでしょう。
方法はともあれとりあえず現状の把握をしてください。

※ちなみに筆者のプロジェクトではsonarcloudを使用していましたが、会社として既に入っていただけのため（入ってただけで当時は特に運用をしてるわけではなかった）特に理由はありません。

## 全体像を把握（タスクに落とし込む）
何かしらのテストカバレッジ測定ツールで各ファイルのカバレッジ率などがわかったら
- 現状テストカバレッジが100％でないファイルは何ファイルあるのか？
- カバーされていない行は何ステップあるのか？
    - ファイルのコード行数 * ファイルのカバレッジ率　= ざっくりとしたカバーされていない行数
- どのディレクトリを100%までカバレッジを上げることができたら全体ではN％カバレッジが上昇するか

あたりを数値化することで全体感の把握をしましょう。
これらを先に把握しておくことで工数や目標設定を行うときにかなり役立つと思います。

## リーダーと目標のすり合わせを行う

そもそもとして
- テストカバレッジを何%まで上げるべきか？
- どのディレクトリのコードに対して、どの粒度のテストを書くべきか？

はそれぞれのプロジェクトによって大きく左右されるところです。

例えば筆者のチームは最終的には
- 対象ディレクトリはサービスのコアロジックに限定
    - 対象: controller, service, domain, model 
    - 対象外: admin-controller, batch...etc
- 全てテストはunitテスト（依存関数は全てmock）
- c1(条件分岐網羅)でカバレッジを100%にすること
- サーバーメンバーは1週間に1ファイルテストカバレッジ上げのお手伝いをしてもらう
    - それを考慮した上でタスクの割り振りをやってもらうようにする

というように落ち着きました。

結果としてこうなったという話をしていますが。。。
- 対象ディレクトリ: 
    - 全てのディレクトリ→サービスのコアロジックのみ
- 閾値: 
    - c0で100%を目指す→c1で100%を目指す

というように、費用対効果を考えながらプロジェクトを進めていく中で細かく調整していきました。

## メンバーに打診する

ここまでは上長とのすり合わせですが、実際に時間を使い、手を動かして対応してくれるのはチームメンバーです。
ここの納得感がかなり重要なためスライドを作成し
- 課題の共有
- プロジェクト全体の目標設定
- 全体のロードマップ
- チームメンバーそれぞれにお願いするタスクの説明
- カバレッジのルール共有

入念に共有とお願いを細かくやっていきました

## 定期的に進捗を共有する会を作る

最初の方は基本的に1人でタスクの管理をやっていたので、2ヶ月目くらいあたりからだれてきてしまったのですが、
その辺りから上長の提案で進捗を1週間に1回短い時間で共有するようにしました。

これのおかげで自分自身しっかりと進捗に向き合うことができましたし、
モチベーションの維持のためにも上長への報告を義務付けることは個人的にはかなり良かったかなと思いました。

# :hand_splayed:どうやってルールを決めた？

テストカバレッジ上げのルールについてはいろいろと紆余曲折ありましたが最終的には

- 1週間で1ファイルのカバレッジを上げる
    - 毎週月曜日に僕自身がNotionベースで対象となるカバレッジファイルのアサインを行なっていました。
     （本当は自動化できるんだったらしたかったw）
- アサインされたカバレッジタスクはc1で100%とする
    - logを出力するだけといった実装とは完全に関係のないところとわかるところなどはカバレッジ対象からignoreすることを許容
- 全てunitテストで行う
    - 基本方針のため意図がある場合は結合テストを書くことも許容
- 下記のに当てはまる関数の場合テストを書かなくても許容する
    - 循環的複雑度で20以上の関数
    - 凝集度が低い関数(手順的凝集かどうか？)
- 何かしら問題が起きた時は全て僕に共有してもらう
    - 僕としては基本的に最優先タスクとして対応を行うこと
  
の5つです。


# :fearful:やってる中で起こった課題は？

大きくは2つの課題がありました
1. ファイルによって辛さが違う
2. 結構みんなやってくれない


## ファイルによって辛さが違う

タスクの割り振りは「ファイル単位」かつ「ランダム」に振り分けを行っていたので、ものによっては
- 1000行を超えるソースコードのテストをアサインしてしまうこと
- そもそもテストファイルすら存在しない

といった1週間で他のタスクと並行しながらこなすには相当きついテストファイルがありました。

### 対応策
対策としては下記3つがありました
1. 通常1週間1ファイルのところを、重いファイルに当たった人は2,3週間でその1ファイルを終わらせてもらう
2. 1ファイルの中の「N行目の〇〇という関数まで」という分け方でタスクを依頼する
3. そもそもアサインのタイミングで重い系のテストは自分が引き受けて他の人にアサインしないようにする

結果としてはテストカバレッジ上げ施策の前半は1の方法、後半は僕自身のメインタスクがテストカバレッジ上げとなったので3番の方法に落ち着いていきました。


## 結構みんなやってくれない

テストカバレッジ上げプロジェクトをやり始めた時はそこまで問題なかったのですが、プロジェクトが始まって3ヶ月あたりくらいから**結構な人がテストカバレッジ上げ**をやってくれなくなりました。

※チームメンバーを悪く言いたいわけではなく、事実としてそうでした。というお話です。それぞれ**メインタスクが忙しくなって**きたり、単純にだれて**モチベーションが下がったり**と、**至極当たり前**の状態です。僕も逆の立場でカバレッジを書き続けることは多分できなかったです

### 対応策

ここの対応策はとてもシンプルで

**僕自身が細かく声掛けをする**

です。
はい、めちゃくちゃシンプルでめちゃめんどくさい方法です

ここで重要なのは、
**「できないこともあるよね〜」**
というスタンスで声をかけることです。
(一応補足ですが、メンバーの能力を低く見るとは違います。)

このスタンスを持って丁寧にお話しして、
自分自身のコミット量をしっかり提示すれば大体の人はコミットしてくれます。
ここは対話の部分なのでそれぞれのコミュニケーションのスタンスにもよるかもですが。
僕の場合はこの形でやってもらってました。

# :scream:失敗するとしたらなぜ失敗するか？

今回僕はたまたまテストカバレッジ上げ施策を最後までやり切ることができましたが、振り返ってみるといずれかの理由で最後までやりきれない可能性は十分にあったと思います。
なので今だからこそ思う失敗する可能性のある要因を2つ共有してきます
1. リーダーのモチベーションが消失
2. テストの優先順位がチーム全体としてとてつもなく下がる

##  リーダーのモチベーションが消失

これは一番可能性のある状態です。
基本的にテストカバレッジをただ上げる作業はやりたくない作業の1つだと思いますし、テストがなくてもアプリケーションは大きなバグが表面化することなく使えていますので優先度が下がりがちです。
そんな中リーダー自身も長期間モチベーションを維持することはとても難しいと思います。
実際僕自身も3,4ヶ月目辺りでだれてきた印象でした

### 対応策

対応策としては
- 仲間を作ること
- 毎週の上長への報告確実に行い締め切りを常に作ること

の2つだと思います。
仲間を作ることはいわばモチベーションの冗長化のようなものだと思っており、これをうまくやっておくと、どちらかがきつくてもどちらかがモチベーションを保つことさえできればうまくやっていけると思います。

2つ目の上長への報告を締め切りとして毎回何かしらの成果をしっかりと持っていこうと思いながらプロジェクトに臨むことで自分自身への締め切り効果を狙っています

## テストの優先順位がプロジェクトチーム全体としてとてつもなく下がる

もしこうなった場合は個人的には仕方ないと思います。
どういった理由であれお金を稼げないサービスは滅びますので一旦サービスを成長させるために

テストカバレッジ上げることは諦めて施策を優先するべきだと思います。
サービスが終了すればテストカバレッジはただの自己満足です。

# :thumbsup:まとめ

テストカバレッジを上げるためにはどうすればいいか？と言う話だったのに、
政治的なところがどうとか、コミュニケーションの仕方がどうとか、タスクの振り方がどう。

みたいな技術的なところとは全く関係ないところにフォーカスが当たってしまいました。。。
まあでも、こういう重要度が高いけどめんどくさい系のお掃除タスクをうまく消化するためには
こういった泥臭い感じのやり方が結局一番進むし、一番成果が出ることなんだろうなと改めて感じました。