できる！じっくり着実、テストプロセス・モダナイゼーションガイド

はじめましてこんにちは。
みなさんの開発環境におけるテスト環境はどんな感じでしょうか？

TDDで実装し、UTおよびE2EがCIで回り、DXかくあるべしと鼻高々で、
そうでない環境は人権侵害であると思っている環境でしょうか？

それとも、こんなんじゃだめだよくないと思いつつ、
テストをプログラマまかせにしている環境でしょうか？

この記事は後者の環境で
現実に立ち向かい、現実を変えたいと思い、
しかし多くの課題を抱え立ちすくんでしまっている有志への応援歌です。

## お前誰？

某SIerで14年目が終わろうとしているエンジニア兼マネージャです。

僕の開発現場は、強力な営業力をもつ現会長が起こしたコンピュータ機器商社で、
20年くらい前から開発部門を自社内に作った、そういう環境です。
エンジニアリングに優れているか、技術的知見が豊富かどうかというよりも、
顧客営業力があるか、納期遵守力があるかどうかが評価基準となる
比較的よくあるSI現場といってもいいでしょう。

品質管理については、入社当時（つまりは14年前）
・プログラマがこれといった指針もなく試験項目を書き、自分で実施する
・カバレッジ（などという概念もなかったが）は、勘と経験と度胸
という状況であり、当然テスト漏れが多く、
開発よりも、トラブルシューティングしている時間のほうが長い環境でした。

僕はその環境を、あるタイミングで3年かけてモダン化しました。
この記事はその時の成功体験、失敗体験をもとに作成しています。

## モダナイゼーション基本戦略

### 性急な改革は行わない

Qiitaのキラキラした環境を全部一足飛びに採用するのはやめましょう。
開発プロセスは、開発現場にいる人間ほとんど全員が実行できないと、
根付かずにいずれ元に戻ってしまいます。

今までと異なる開発プロセスは、それがたとえ工数削減を目指したものであっても、
実行するものにとって、学習コストを強います。

超えられない学習コストを提示すれば、
待つのは挫折か反発か、その両方です。

プロセスの変更は、必ず１つずつ、
場合によっては3か月に１つずつぐらいにとどめましょう。

結局はそれが、一番早くモダナイゼーションが根付きます。

### 言ってみて、やって見せて、させてみて

プロセス改革は上から下に指示するだけでは実現できません。[^1]
[^1]: 上からの押し付けだけでプロセスが改善しないのは、働き方改革が全く進展しない現在の状況をみれば、説明不要ではないかと思います。

改革後のプロセス実行を担う人間は、あなたとは違う主義主張・趣味嗜好をもった人間です。
そもそもあなたと問題意識を共有していませんし、
従って、改革意欲（＝負担できる学習コスト）は人によって異なります。
当然、あなたとは知識・経験・スキルの偏りは違うので、
必要な学習コストも異なります。

崖を乗り越える力も、崖の大きさも人によって大きく違います。

この意欲の差を無視したら、少数のチームであっても新プロセスの定着は困難です。

チーム全員を崖の向こう側に導くには、

* 言ってみて
    * 意義を語り、意欲を育み
* やって見せて
    * お手本があることで、学習コストを低減させて
* させてみて
    * 実際にやっている最中に、躓きをフォローし学習コストを下げる
    * できたという体験が意欲を増加させる

が必要であり、改革者による率先垂範と寄り添いが必要です。

### 許可を求めるな、謝罪せよ[^2]

[^2]: 計算機械学の偉人 グレース・ホッパー准将（[wikipedia](https://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%AC%E3%83%BC%E3%82%B9%E3%83%BB%E3%83%9B%E3%83%83%E3%83%91%E3%83%BC)）の言葉。

新しい試みに、許可を求めてはいけません。
新しい試みは、コストがかかることは確定しています。
一方で成果は不確実です。少なくとも、あなた以外には不確実に見えます。

そうすると、コスト・リターン比率は、どうしても悪く見えますので、
賢い人ほど、不許可をだします。
決め台詞は「もっと他にやるべきことがあるだろう」です。

ジョブズ氏はiPhoneをだれかの許可を取りながら作ったでしょうか？
ザッカーバーグ氏はどうでしょう？

新しいことを行うのに、許可を求めてはいけません。
許可を求めて行うよりも、やってみて失敗したら謝罪してもとに戻すほうが、
よっぽど世界を、現場を変えられることは、
歴史が証明していますし、私は経験でそれを実感しています。

## テストプロセス・モダナイゼーション

### 前提

以下の環境を前提としています。
環境が異なる場合は、適宜ステップを変更してください。

* いかなるテスト自動化もしていない
* 3 ～ 7人程度の開発チーム
* 常に時間が足りない
* QAチームは存在しない
* 品質指標は存在しない
* ドメイン知識はあるが、テストに関する知識はほとんどない
* 人員を増員することも、テストに詳しい人員に入れ替えることも困難
* 6か月に１回以上のリリースを行っている

### モダナイゼーションステップ

#### 1. リリース後障害統計を作成し、更新する

統計をとるだけでは品質は1ミリも改善しません。
しかし、統計がないとこの先の改革効果が明示されず、
従って改革がドライブしません。場合によってはいつか、心が折れてしまいます。

統計項目は、原因となった開発・機能名、対処コストは絶対に入れましょう。
逆にあまり増やしすぎてはいけません。

月一ぐらいで定期的に更新し、朝会などで共有しましょう。

#### 2. 単体テスト、結合試験のテスト項目数、摘出バグ数、バグ率統計を作成する

統計項目数は、最初は上記3項目ぐらいにして、軌道に乗ったら徐々に増やしましょう

#### 3. 統計から教訓を読み取る
データがたまってきたら、リリース後障害と、
単体テスト・結合テストのテスト項目数、バグ率に緩い相関があることがわかります。

通常は、「開発規模・難易度に比してテスト項目数が少ない」
「バグ率が他と比べて高すぎる・低すぎる」開発・機能に、リリース後障害が偏ることが見えるはずです。

これも定期的に朝会などで共有しましょう

#### 4. テスト結果評価および、強化試験をプロセスに組み込む

テスト項目数とバグ率が、一定の基準を満たさない限り、
確率論的にリリース後障害でどの程度の対処コストが発生するかがわかれば、
不毛なことに時間を割かなくてもいいよう、強化試験をすることに反対されなくなります。

メンバーを説得し、強化試験実施基準を策定し、
基準を通過できなければ強化試験をする改革を断行しましょう

この改革は、過去原因の不具合対応が出続ける中、
未来の不具合を減らす過負荷状態に一時的に陥ります。
可能であれば、追加要員・追加スケジュールを獲得しましょう。

#### 5. テスト項目レビューを実施する

4の強化試験が定着すると、リリース後障害が一定数減り、不毛な障害対応が減るでしょう。
この一定の手ごたえと成功体験をメンバーがつかんだら、
それでも発生したリリース後障害を分析しましょう。

そうすると、テスト項目の品質が高くないと、
「テスト項目数、バグ率の基準」が無意味になることに気づきます。
テスト項目数は、意味のない項目でいくらでも水増しできるし、
母集団が無意味ならバグ率も無意味になるからです。

メンバーがこの共通認識に至ったら、プロセスにテスト項目レビューを行うチャンスです。
すかさずプロセス追加を行いましょう

ピアレビューが負荷分散としては理想ですが、
ドメイン知識、テスト知識に偏りがある場合は、テックリードもしくはPMが実施しましょう。
テスト項目レビューを一部の人間が負担する場合、負荷の限界を超える場合があるので、
担当業務を適宜他のメンバーに移譲しましょう

#### 6. テスト項目を階層化する（テスト設計とテスト実装とに分離する）

テスト項目レビューを行うようになると、30項目ぐらいのテストならいざ知らず、
100項目ぐらいのテストになるともはや、漏れがあるのかないのか
判断不能であることに気づくでしょう

そこで、テスト項目を階層化することを提案しましょう
例えば

> * 画面A
    * テスト項目１
    * テスト項目２
* 画面B
    * テスト項目３
    * テスト項目４

もっと言えば、

> * 画面A
    * 初期表示
        * 表示内容
            * 項目α
                * テスト項目１
                * テスト項目２
            * 項目β
                * ・・・
        * ・・・
    * 更新ボタンクリック
        * 入力チェック
            * 項目α
                * テスト項目３
                * テスト項目４
            * 項目β
                * ・・・・
        * データ登録
            * ・・・
* 画面B
    * ・・・

ぐらい階層化しましょう。

そして第３階層くらいまで作ったらいったんレビューし、
大きな抜けがないことを確認してから実際のテスト項目を作り出すようにしましょう。

このテスト設計とテスト実装との分離は、
レビューする側はもちろん、テスト項目の作成者にとっても、
脳内が整理され、ワーキングメモリーが節約できるため、
精神的負荷が著しく軽減されるため、一度やると反対はでなくなります。

ただし、最初は反対が出る可能性があるので、初回は寄り添って支援してあげましょう。

#### 7. ソースコードをレビューする

6まで進めると、リリース後障害がかなり減るでしょう。
そして、それでも発生するリリース後障害を観測すると、
以下の２種類の問題が取り切れていないことに気づくでしょう。

1. ソースコードが腐ってると、テストでバグを見つけても直しきれない
2. これまでのテストプロセスでは、非機能試験（性能、セキュリティ、運用性etc）が行われていない

1については、ソースコードレビュー[^3]を行いましょう。
[^3]: なお、ソースコードレビューは、テストではないのでは？という質問をいつも受けますが、JSTQBの基準に則れば、静的テストというれっきとしたテストです。

ソースコードレビューの方法論については、
最初はざっくり見ただけレベルでも大丈夫です。
以前[こんな記事](https://qiita.com/gakuri/items/f4970aea8de5fa9bf016)を投稿しましたが、いきなりこのレベルでやってはいけません。

ちょっとずつプロセスを変え、後工程の時間短縮という成果が出たら、
それを再投資していく形で、レビュー改善を進めましょう

#### 8. 非機能観点のレビューを実施する

非機能試験については、[こちら](https://qiita.com/gakuri/items/53a0802ab82115501473#%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E5%93%81%E8%B3%AA%E7%89%B9%E6%80%A7)を参考にしてください。

まずは試験項目に試験すべき非機能観点が含まれるか、
（負荷試験など別のテストフェーズに切り出されている場合もあるが）
からはじめ、ソースレビュー・設計レビュー・要件開発などに広げていきます。

これも一気に進めてはいけません。

#### 9. E2E自動テストを導入する 

8まで改革が進めば、障害等などの後ろ向きの対応が減り、
改革者としてのあなたは評価されはじめ、
たとえ大変なことであっても、メンバーは協力をしてくれるでしょう。

いよいよ自動テストの出番です。

E2Eとは実際にブラウザを自動で動かす方式のテストで、
WEBアプリケーションではSeleniumが最も有名です。

まずは、シナリオ１個、手動実行から始めましょう。
完璧を目指すのはやめましょう。E2Eテストに完璧はありません。
まずは実行されている状況を作るのが大事です。
実行されていれば、そこにシナリオをつぎ足すのは難しくありません。

なおE2Eテストすれば人間による動作テストがすべてなくなるわけではありません。
人間による動作テストが変なところで躓かなくなったり
機械的に見る部分が縮小できる効果はありますが、
大きくコスト削減はしません。

あくまで私の意見ですが、
E2E導入の目的はコスト削減ではなく、品質向上に置くべきです。

#### 10. UT自動テストを導入する

UT（ユニットテスト）は、関数単位で妥当性を検証する自動テストで、
JavaであればjUnit、.net系であれば nUnit など、
およそほとんどの言語で誰かしらが提供してくれています。

これも、完璧を目指してはいけません。
ユニットテストは、やろうと思えば分岐網羅をすべてテストさせることが可能ですが、
いきなり完全を目指そうとしてはいけません。

作るのに挫折するどころか、実行でエラーが出すぎて挫折します。

まずは、重要な部分、過去障害が起きた部分をピックアップし、
C0未満のカバレッジでもいいから、ちょっとずつ増やしていきましょう。

なおUTすれば人間による動作テストが（以下略

#### 11. ゆるくTDDを導入する

メンバーの大半がUTを複数回触ったことがあるという状況をつくったら、
ゆるくTDDを導入しましょう。

新設したすべての関数にUTを入れることを義務付けるが、
新設でない修正関数はプログラマにお任せ、
UTの密度についてもプログラマに任せる方式で、
[@t_wada](https://twitter.com/t_wada)さんの前では、[決して言えない](https://twitter.com/tacck/status/1139694730709594113)が、
やらない完全よりもやるゆるふわの精神で進めましょう。

#### 12. CIソフトウェアを導入する

CI（Continuous Integration）ソフトウェアとは、
定期的にもしくはイベント駆動でGit/SVNから、
エクスポート、ビルド、デプロイ、自動テストなどを、
自動で実施してくれるソフトウェアで、
かつ、その実行結果を統合管理してくれる点が、
ただのタスクランナーとは異なります。

有名なところでいうとJenkinsやCircleCI、
AWS CodeBuildやAzure DevOpsなどがあります。

複数の自動テストが走り始めると、
個別に実行、個別に結果確認が苦しくなってくるので、
CIソフトウェアを導入しましょう

別に自動テストに先立ってCIを導入してもよいですが
間違ってもCIがないから自動テストできないわけではないので、
導入順序の依存関係に留意してください。

#### 最後. テストプロセス改善ミーティングを定期開催する

各プロセスを導入し効果が出たら、あるいはその最中から、
メンバーに改善の楽しさが芽生えやり方も覚え、創意工夫が出てくるはずです。

月一または週一で、「次はどんな改善をしたらハッピーになれるか」
という議題でミーティングをし、改革の主導権を移譲していきましょう。

あなた自身は、メンバーから出る完璧主義を排除したり、
失敗時の挫折防止に役割をスライドさせましょう。

そうでなければ、あなたがいなくなった瞬間、プロセスが劣化していきます。

## がんばれ改革者！

改革は大変です。
多大な献身を求められ、最初は支援者もなく、評価してくれる人もいません。
時には責められ、反乱を起こされることもあるでしょう。
成功しても、すべてがあなたの手柄にはなりません。
全く割に合わないことこの上ありません。

それでも、私はこの割に合わない改革を進めていこうと思います。
そうすることがエンジニアとして生きていく唯一の方法だと思うからです。

今流行りの開発手法、アーキテクチャ、テスト手法は、
これまでどおり、10年後には別の方法にとってかわられているでしょう。

理想の開発手法・アーキテクチャ・テスト手法は、きっと変わり続けるのであり、
自らを、チームを、現場を変え続けられる人間のみが、
エンジニアとして生き続けられるのだと私は思っています。

今、モダンでない環境で開発しているあなたは、
変え続ける経験を積める、変え続ける力を身に着ける
チャンスかもしれません。

むしろエンジニアとして初めての開発で「今のモダン」方式を覚え、
旧方式のエンジニアを「昭和脳」と罵っているだけの人のほうが、
変化に対応し続ける能力を身に着けられず、
10年後、さらに「新しいモダン」を覚えた人に、罵られることになるかもしれません。

あなたのやっていることは無駄ではありません。
無駄にはなりません。

健闘を祈ります。